diff options
198 files changed, 7709 insertions, 3075 deletions
diff --git a/.appveyor.yml b/.appveyor.yml index 22124121..1ed5214c 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -12,4 +12,4 @@ build_script: C:\msys64\usr\bin\bash -lc "./packaging/msys2-build.sh" artifacts: - name: Installer - path: build/Mana-*-win64.exe + path: Mana-*-win64.exe diff --git a/CMakeLists.txt b/CMakeLists.txt index 115c2914..c80a5abd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,6 +26,8 @@ set(CMAKE_CXX_STANDARD_REQUIRED True) # where to look for cmake modules set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/CMake/Modules) +set(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME ${PROJECT_NAME}) + find_package(Gettext) option(WITH_OPENGL "Enable OpenGL support" ON) @@ -167,5 +169,23 @@ if(WIN32) $ENV{MINGW_PREFIX}/bin/libpcre2-8-0.dll $ENV{MINGW_PREFIX}/bin/libxmp.dll DESTINATION ${CMAKE_INSTALL_BINDIR}) + + # Install portable.xml as part of an optional Portable component + set(CPACK_COMPONENT_PORTABLE_DISPLAY_NAME "Portable") + set(CPACK_COMPONENT_PORTABLE_DESCRIPTION "Portable mode. Settings and updates are stored in the installation folder.") + set(CPACK_COMPONENT_PORTABLE_DISABLED TRUE) + install( + FILES "${CMAKE_SOURCE_DIR}/packaging/windows/portable.xml" + DESTINATION ${CMAKE_INSTALL_BINDIR} + COMPONENT Portable + ) endif() + +set(CPACK_COMPONENT_MANA_DISPLAY_NAME "${PROJECT_NAME}") +set(CPACK_COMPONENT_MANA_DESCRIPTION "${PROJECT_DESCRIPTION}.") +set(CPACK_COMPONENT_MANA_REQUIRED TRUE) + +set(CPACK_COMPONENT_TRANSLATIONS_DISPLAY_NAME "Translations") +set(CPACK_COMPONENT_TRANSLATIONS_DESCRIPTION "Translations for the user interface. Without these only English will be available.") + include(CPack) @@ -2,6 +2,7 @@ - Ported to SDL 2 - Added VSync and windowed fullscreen options - Added support for scaling the graphics +- Added NPC quest indicators and a Quests window - Added ability to open external links in news, chat and NPC dialogs - Added ability to mention assigned keys in NPC dialogs - Added support for text formatting to NPC dialogs @@ -33,8 +34,10 @@ - Re-download updates when their checksum no longer matches - Enabled resizing windows from all sides - Enabled whispers in tabs by default +- Improved quality of outlined text rendering - Made pickup notifications to appear as particle instead of text by default - Made names update immediately when changing "Show gender" option +- Made the screenshot file name a clickable link - Made client config statically typed and save as more structured XML - Custom mouse cursor is now rendered by the system - Limit shop's Max button to available carry weight @@ -61,6 +64,8 @@ - Fixed storing of player relations - Fixed handling of custom port in update URL - Fixed stutter when new music starts playing +- Fixed keyboard setup to allow assigning keys before starting the game +- Fixed window move/resize blocking logic and rendering on Windows and macOS - Updated to tmwAthena protocol changes - Updated to Manaserv protocol changes (specials, guilds, debug mode, skills, text particles) - CMake: Use GNUInstallDirs and made PKG_DATADIR / PKG_BINDIR paths modifiable diff --git a/data/graphics/gui/button-icon-quests.png b/data/graphics/gui/button-icon-quests.png Binary files differnew file mode 100644 index 00000000..4c2fbd3b --- /dev/null +++ b/data/graphics/gui/button-icon-quests.png diff --git a/data/graphics/gui/jewelry/theme.xml b/data/graphics/gui/jewelry/theme.xml index aa965d07..2b4911de 100644 --- a/data/graphics/gui/jewelry/theme.xml +++ b/data/graphics/gui/jewelry/theme.xml @@ -10,13 +10,13 @@ <color id="BORDER" color="#000000" /> <color id="DROPDOWN" color="#000000" /> <color id="LISTBOX" color="#000000" /> - <color id="LISTBOX_SELECTED" color="#000000" /> <color id="CHANNEL_CHAT_TAB" color="#efd7a7" outlineColor="#473005" /> <color id="BACKGROUND" color="#ffffff" /> <color id="BACKGROUND_GRAY" color="#404040" /> <color id="DROPDOWN_SHADOW" color="#c0c0c0" /> <color id="HIGHLIGHT" color="#ebc873" /> - <color id="TAB_FLASH" color="#fec4ff" effect="pulse" /> + <color id="HIGHLIGHT_TEXT" color="#000000" /> + <color id="TAB_FLASH" color="#a7ff2a" outlineColor="#142200" effect="pulse" /> <color id="TAB_PLAYER_FLASH" color="#00ff00" effect="pulse" /> <color id="PARTY_TAB" color="#efd7a7" outlineColor="#473005" /> <color id="GUILD_TAB" color="#efd7a7" outlineColor="#473005" /> @@ -26,7 +26,6 @@ <color id="WHISPER_TAB_OFFLINE_SELECTED" color="#444444" outlineColor="#000000" /> <color id="SHOP_WARNING" color="#e07a7a" /> <color id="ITEM_EQUIPPED" color="#000091" /> - <color id="ITEM_NOT_EQUIPPED" color="#000000" /> <color id="CHAT" color="#f1d9a9" /> <color id="GM" color="#fec4ff" /> <color id="GLOBAL" color="#fec4ff" /> @@ -93,7 +92,6 @@ <color id="BORDER" color="#000000" /> <color id="DROPDOWN" color="#000000" /> <color id="LISTBOX" color="#000000" /> - <color id="LISTBOX_SELECTED" color="#000000" /> <color id="CHANNEL_CHAT_TAB" color="#efd7a7" outlineColor="#473005" /> <color id="TAB_FLASH" color="#a7ff2a" outlineColor="#142200" /> <color id="TAB_PLAYER_FLASH" color="#ff96f6" /> @@ -101,9 +99,9 @@ <color id="BACKGROUND_GRAY" color="#404040" /> <color id="DROPDOWN_SHADOW" color="#c0c0c0" /> <color id="HIGHLIGHT" color="#ebc873" /> + <color id="HIGHLIGHT_TEXT" color="#000000" /> <color id="SHOP_WARNING" color="#e07a7a" /> <color id="ITEM_EQUIPPED" color="#000091" /> - <color id="ITEM_NOT_EQUIPPED" color="#000000" /> <color id="BUBBLE_NAME" color="#cccccc" /> <color id="BUBBLE_TEXT" color="#ffffff" /> <color id="LOGGER" color="#919191" /> @@ -171,17 +169,16 @@ <color id="BORDER" color="#000000" /> <color id="DROPDOWN" color="#000000" /> <color id="LISTBOX" color="#000000" /> - <color id="LISTBOX_SELECTED" color="#000000" /> <color id="CHANNEL_CHAT_TAB" color="#efd7a7" outlineColor="#000000" /> <color id="BACKGROUND" color="#ffffff" /> <color id="BACKGROUND_GRAY" color="#404040" /> <color id="DROPDOWN_SHADOW" color="#c0c0c0" /> <color id="HIGHLIGHT" color="#ebc873" /> + <color id="HIGHLIGHT_TEXT" color="#000000" /> <color id="TAB_FLASH" color="#fec4ff" effect="pulse" /> <color id="TAB_PLAYER_FLASH" color="#00ff00" effect="pulse" /> <color id="SHOP_WARNING" color="#e07a7a" /> <color id="ITEM_EQUIPPED" color="#000091" /> - <color id="ITEM_NOT_EQUIPPED" color="#000000" /> <color id="CHAT" color="#f1d9a9" /> <color id="GM" color="#fec4ff" /> <color id="GLOBAL" color="#fec4ff" /> @@ -499,7 +496,7 @@ </state> </skin> - <skin type="ShortcutBox" width="36" height="42"> + <skin type="ShortcutBox" padding="2" width="36" height="42"> <state> <img src="window.png" x="58" y="75" width="36" height="42" /> </state> @@ -539,4 +536,7 @@ <icon name="offline" src="window.png" x="65" y="164" width="13" height="13" /> <icon name="online" src="window.png" x="49" y="164" width="13" height="13" /> + + <icon name="complete" src="window.png" x="1" y="223" width="20" height="18" /> + <icon name="incomplete" src="window.png" x="23" y="223" width="20" height="18" /> </theme> diff --git a/data/graphics/gui/quest-icons.png b/data/graphics/gui/quest-icons.png Binary files differnew file mode 100644 index 00000000..a35566a0 --- /dev/null +++ b/data/graphics/gui/quest-icons.png diff --git a/data/graphics/gui/theme.xml b/data/graphics/gui/theme.xml index 3ed93c6e..fc1de9e3 100644 --- a/data/graphics/gui/theme.xml +++ b/data/graphics/gui/theme.xml @@ -17,6 +17,7 @@ <color id="WHISPER_TAB" color="#3b58a9" /> <color id="BACKGROUND" color="#ffffff" /> <color id="HIGHLIGHT" color="#c0c0c0" /> + <color id="HIGHLIGHT_TEXT" color="#000000" /> <color id="TAB_FLASH" color="#ff0000" effect="pulse" /> <color id="SHOP_WARNING" color="#910000" /> <color id="ITEM_EQUIPPED" color="#000091" /> @@ -334,4 +335,7 @@ <icon name="offline" src="circle-gray.png" /> <icon name="online" src="circle-green.png" /> + + <icon name="complete" src="quest-icons.png" x="0" y="0" width="16" height="16" /> + <icon name="incomplete" src="quest-icons.png" x="16" y="0" width="16" height="16" /> </theme> diff --git a/packaging/msys2-build.sh b/packaging/msys2-build.sh index 209e725f..aa09425a 100755 --- a/packaging/msys2-build.sh +++ b/packaging/msys2-build.sh @@ -14,5 +14,4 @@ pacman --noconfirm -S \ cmake -B build . -DUSE_SYSTEM_GUICHAN=OFF -DCMAKE_BUILD_TYPE=Release cmake --build build -pushd build -cpack +cpack --config build/CPackConfig.cmake diff --git a/po/CMakeLists.txt b/po/CMakeLists.txt index e0cfc325..6ae6e9e0 100644 --- a/po/CMakeLists.txt +++ b/po/CMakeLists.txt @@ -31,7 +31,8 @@ macro(MANA_GETTEXT_CREATE_TRANSLATIONS _potFile _firstPoFileArg) install( FILES ${_gmoFile} DESTINATION ${CMAKE_INSTALL_LOCALEDIR}/${_lang}/LC_MESSAGES - RENAME ${_potBasename}.mo) + RENAME ${_potBasename}.mo + COMPONENT Translations) set(_gmoFiles ${_gmoFiles} ${_gmoFile}) endforeach(_currentPoFile) @@ -3785,7 +3785,7 @@ msgstr "" #: ../src/net/tmwa/playerhandler.cpp:128 msgid "" "You've shuffled off your mortal coil, run down the curtain and joined the " -"bleedin' choir invisibile." +"bleedin' choir invisible." msgstr "" #: ../src/net/tmwa/playerhandler.cpp:125 @@ -3740,7 +3740,7 @@ msgstr "" #: ../src/net/tmwa/playerhandler.cpp:128 msgid "" "You've shuffled off your mortal coil, run down the curtain and joined the " -"bleedin' choir invisibile." +"bleedin' choir invisible." msgstr "" #: ../src/net/tmwa/playerhandler.cpp:125 @@ -3746,7 +3746,7 @@ msgstr "" #: ../src/net/tmwa/playerhandler.cpp:128 msgid "" "You've shuffled off your mortal coil, run down the curtain and joined the " -"bleedin' choir invisibile." +"bleedin' choir invisible." msgstr "" #: ../src/net/tmwa/playerhandler.cpp:125 @@ -3847,7 +3847,7 @@ msgstr "" #: ../src/net/tmwa/playerhandler.cpp:128 msgid "" "You've shuffled off your mortal coil, run down the curtain and joined the " -"bleedin' choir invisibile." +"bleedin' choir invisible." msgstr "" #: ../src/net/tmwa/playerhandler.cpp:125 @@ -3986,7 +3986,7 @@ msgstr "Du har stillet træskoene." #: ../src/net/tmwa/playerhandler.cpp:128 msgid "" "You've shuffled off your mortal coil, run down the curtain and joined the " -"bleedin' choir invisibile." +"bleedin' choir invisible." msgstr "Du har spist af dødens pølse for den sidste gang." #: ../src/net/tmwa/playerhandler.cpp:125 @@ -3864,7 +3864,7 @@ msgstr "Jetzt passt Du in 'nen Eimer." #: ../src/net/tmwa/playerhandler.cpp:128 msgid "" "You've shuffled off your mortal coil, run down the curtain and joined the " -"bleedin' choir invisibile." +"bleedin' choir invisible." msgstr "" "Du hast Deine sterbliche Hülle abgelegt, der Schleier legt sich über Dich " "und Du trittst dem Chor der blutenden Unsichtbaren bei." diff --git a/po/en_GB.po b/po/en_GB.po index 4deb48cd..df45f3e1 100644 --- a/po/en_GB.po +++ b/po/en_GB.po @@ -3973,10 +3973,10 @@ msgstr "You've kicked the bucket." #: ../src/net/tmwa/playerhandler.cpp:128 msgid "" "You've shuffled off your mortal coil, run down the curtain and joined the " -"bleedin' choir invisibile." +"bleedin' choir invisible." msgstr "" "You've shuffled off your mortal coil, run down the curtain and joined the " -"bleedin' choir invisibile." +"bleedin' choir invisible." #: ../src/net/tmwa/playerhandler.cpp:125 msgid "Your metabolic processes are now history." @@ -3738,7 +3738,7 @@ msgstr "" #: ../src/net/tmwa/playerhandler.cpp:128 msgid "" "You've shuffled off your mortal coil, run down the curtain and joined the " -"bleedin' choir invisibile." +"bleedin' choir invisible." msgstr "" #: ../src/net/tmwa/playerhandler.cpp:125 @@ -10,7 +10,7 @@ msgstr "" "Project-Id-Version: Mana\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2024-10-23 09:58+0200\n" -"PO-Revision-Date: 2024-10-23 07:12+0000\n" +"PO-Revision-Date: 2024-12-01 15:00+0000\n" "Last-Translator: gallegonovato <fran-carro@hotmail.es>\n" "Language-Team: Spanish <https://hosted.weblate.org/projects/mana/mana/es/>\n" "Language: es\n" @@ -18,23 +18,25 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 5.8.2-dev\n" +"X-Generator: Weblate 5.9-dev\n" #: ../src/main.cpp:52 msgid " to the mana client." -msgstr "" +msgstr " al cliente de maná." #: ../src/main.cpp:51 msgid " used to set custom parameters" -msgstr "" +msgstr " Se utiliza para establecer parámetros personalizados" #: ../src/main.cpp:70 msgid " --chat-log-dir : Chat log dir to use" -msgstr "" +msgstr " --chat-log-dir : Directorio de registro de chat para usar" #: ../src/main.cpp:69 msgid " --localdata-dir : Directory to use as local data directory" msgstr "" +" --localdata-dir : Directorio que se utilizará como directorio de datos " +"local" #: ../src/main.cpp:73 msgid " --no-opengl : Disable OpenGL for this session" @@ -93,9 +95,8 @@ msgid " -v --version : Display the version" msgstr " -v --version : Muestra la versión" #: ../src/main.cpp:63 -#, fuzzy msgid " -y --server-type : Login server type" -msgstr " -s --server : Login server o IP" +msgstr " -y --server-type : Tipo de servidor de inicio de sesión" #: ../src/gui/updaterwindow.cpp:410 msgid "##1 It is strongly recommended that" @@ -137,7 +138,7 @@ msgstr "%d FPS (OpenGL)" #: ../src/gui/setup_video.cpp:178 #, c-format msgid "%dx" -msgstr "" +msgstr "%dx" #: ../src/client.cpp:1074 ../src/client.cpp:1097 #, c-format @@ -200,35 +201,35 @@ msgid "%s is now a member of your party." msgstr "%s ahora es un miembro de tu grupo." #: ../src/net/manaserv/partyhandler.cpp:129 -#, fuzzy, c-format +#, c-format msgid "%s joined the party on invitation from %s." -msgstr "Cancelada la invitación de %s." +msgstr "%s se unio a la fiesta por invitación de %s." #: ../src/net/manaserv/partyhandler.cpp:127 -#, fuzzy, c-format +#, c-format msgid "%s joined the party." -msgstr "%s se unio al grupo party%s" +msgstr "%s se unió a la fiesta." #: ../src/net/manaserv/chathandler.cpp:319 #, c-format msgid "%s left the channel." -msgstr "%s dejó el canal." +msgstr "%s abandonó el canal." #: ../src/net/tmwa/partyhandler.cpp:123 #, c-format msgid "%s refused your invitation." -msgstr "%s cancelo tu invitación." +msgstr "%s rechazó tu invitación." #: ../src/net/manaserv/partyhandler.cpp:151 #, c-format msgid "%s rejected your invite." -msgstr "%s canceló tu invitación." +msgstr "%s rechazó tu invitación." #: ../src/net/manaserv/tradehandler.cpp:116 #: ../src/net/tmwa/tradehandler.cpp:110 #, c-format msgid "%s wants to trade with you, do you accept?" -msgstr "%s quiere comerciar contigo, aceptas?" +msgstr "%s quiere comerciar contigo, ¿aceptas?" #: ../src/gui/widgets/chattab.cpp:186 #, c-format @@ -312,14 +313,12 @@ msgid "/kick > Kick a user from the channel" msgstr "/kick > Expulsar un usuario del canal" #: ../src/net/tmwa/gui/guildtab.cpp:56 -#, fuzzy msgid "/kick > Kick someone from the guild you are in" -msgstr "/kick > Expulsa a alguien del clan en el que estás." +msgstr "/kick > Expulsar a alguien del gremio en el que estás" #: ../src/net/tmwa/gui/partytab.cpp:55 -#, fuzzy msgid "/kick > Kick someone from the party you are in" -msgstr "/kick > Expulsa a alguien del grupo en el que estás" +msgstr "/kick > Expulsar a alguien del grupo en el que estás" #: ../src/net/tmwa/gui/guildtab.cpp:55 msgid "/leave > Leave the guild you are in" @@ -574,7 +573,7 @@ msgstr "Ya se está llevando a cabo la grabación." #: ../src/gui/setup_video.cpp:246 msgid "Ambient FX:" -msgstr "" +msgstr "Ambient FX:" #: ../src/net/tmwa/inventoryhandler.h:84 msgid "Ammo" @@ -599,16 +598,16 @@ msgid "Applying change to OpenGL requires restart." msgstr "Aplicar el intercambio a OpenGL requiere reiniciar el juego." #: ../src/gui/setup_video.cpp:386 -#, fuzzy msgid "" "Applying change to OpenGL requires restart.\n" "\n" "In case OpenGL messes up your game graphics, restart the game with the " "command line option \"--no-opengl\"." msgstr "" -"Cambiar a OpenGL necesita reiniciar el cliente. En caso de OpenGL atrape tus " -"graficos, abra el juego atraves de linea de comando con la seguinte opcion: " -"\"--no-opengl\"." +"Aplicar cambios a OpenGL requiere reiniciar el juego.\n" +"\n" +"En caso de que OpenGL estropee los gráficos de tu juego, reinicia el juego " +"con la opción de línea de comandos «--no-opengl»." #: ../src/gui/charselectdialog.cpp:66 msgid "Are you sure you want to delete this character?" @@ -635,7 +634,7 @@ msgstr "Atribuir" #: ../src/net/manaserv/charhandler.cpp:166 #, c-format msgid "At least one stat is out of the permitted range: (%u - %u)." -msgstr "" +msgstr "Al menos una estadística está fuera del rango permitido: (%u - %u)." #: ../src/keyboardconfig.cpp:46 ../src/net/tmwa/generalhandler.cpp:236 msgid "Attack" @@ -666,7 +665,7 @@ msgstr "Fallo en la autentificación." #: ../src/gui/setup_video.cpp:176 #, c-format msgid "Auto (%dx)" -msgstr "" +msgstr "Automático (%dx)" #: ../src/localplayer.cpp:1023 msgid "Away" @@ -682,21 +681,20 @@ msgid "Being" msgstr "Personaje" #: ../src/gui/debugwindow.cpp:141 -#, fuzzy msgid "Being Ids" -msgstr "Personaje" +msgstr "ID de personajes" #: ../src/gui/debugwindow.cpp:137 msgid "Being collision radius" -msgstr "" +msgstr "Siendo el radio de colisión" #: ../src/gui/debugwindow.cpp:139 msgid "Being path" -msgstr "" +msgstr "Ser trayectoria" #: ../src/gui/debugwindow.cpp:138 msgid "Being positions" -msgstr "" +msgstr "Siendo posiciones" #: ../src/net/tmwa/playerhandler.cpp:123 msgid "Bereft of life, you rest in peace." @@ -749,9 +747,8 @@ msgstr "" "existe, o eres tú." #: ../src/gui/socialwindow.cpp:662 -#, fuzzy msgid "Cannot create party. You are already in a party." -msgstr "No se pudo crear un grupo. Ya estás en uno." +msgstr "No se puede crear un grupo. Ya estás en uno." #: ../src/net/tmwa/playerhandler.cpp:361 msgid "Cannot raise skill!" @@ -906,7 +903,7 @@ msgstr "Cerrar" #: ../src/gui/debugwindow.cpp:136 msgid "Collision tiles" -msgstr "" +msgstr "Mosaicos de colisión" #: ../src/gui/setup_colors.cpp:48 msgid "Colors" @@ -1140,9 +1137,8 @@ msgid "Could not steal anything..." msgstr "No puedes robar nada..." #: ../src/game.cpp:290 -#, fuzzy msgid "Could not take screenshot!" -msgstr "No es posible crear un grupo." +msgstr "¡No se pudo hacer la captura de pantalla!" #: ../src/gui/charcreatedialog.cpp:85 ../src/gui/charselectdialog.cpp:393 #: ../src/gui/socialwindow.cpp:365 @@ -1189,17 +1185,16 @@ msgid "Cursor: (%d, %d)" msgstr "Cursor: (%d, %d)" #: ../src/gui/setup_video.cpp:102 -#, fuzzy msgid "Custom" -msgstr "Servidor propio" +msgstr "Personalizado" #: ../src/gui/customserverdialog.cpp:50 msgid "Custom Server" -msgstr "Servidor propio" +msgstr "Servidor personalizado" #: ../src/gui/setup_video.cpp:229 msgid "Custom cursor" -msgstr "Cursor propio" +msgstr "Cursor personalizado" #: ../src/gui/setup_video.cpp:393 msgid "Deactivating OpenGL" @@ -1464,23 +1459,18 @@ msgid "Failed adding item. Trade partner is over weighted." msgstr "Error al añadir objeto. El otro jugador lleva mucho peso." #: ../src/net/tmwa/tradehandler.cpp:214 -#, fuzzy msgid "Failed adding item. You can't trade this item." -msgstr "" -"Fallo al añadir objeto. No puedes añadir más de un mismo tipo de objeto en " -"la ventana." +msgstr "Error al agregar el artículo. No puedes intercambiar este artículo." #: ../src/gui/tradewindow.cpp:262 -#, fuzzy msgid "Failed adding item. You cannot overlap one kind of item on the window." msgstr "" -"Fallo al añadir objeto. No puedes añadir más de un mismo tipo de objeto en " +"Error al agregar un elemento. No se puede superponer un tipo de elemento en " "la ventana." #: ../src/gui/setup_video.cpp:374 -#, fuzzy msgid "Failed to change video mode." -msgstr "Fallo al usar el objeto." +msgstr "No se pudo cambiar el modo de vídeo." #: ../src/net/tmwa/charserverhandler.cpp:136 msgid "Failed to create character. Most likely the name is already taken." @@ -1535,7 +1525,6 @@ msgid "Friend" msgstr "Amigo" #: ../src/gui/setup_video.cpp:221 -#, fuzzy msgid "Fullscreen" msgstr "Pantalla completa" @@ -1545,12 +1534,11 @@ msgstr "Nombres De Los GMs" #: ../src/gui/debugwindow.cpp:142 msgid "GUI debug" -msgstr "" +msgstr "Depuración de GUI" #: ../src/gui/setup_interface.cpp:112 -#, fuzzy msgid "GUI opacity" -msgstr "Opacidad" +msgstr "Opacidad de la GUI" #: ../src/net/tmwa/gamehandler.cpp:89 msgid "Game" @@ -1608,9 +1596,8 @@ msgid "Guild created." msgstr "Clan creado." #: ../src/net/tmwa/guildhandler.cpp:63 -#, fuzzy msgid "Guild creation isn't supported." -msgstr "La creación de guilds no esta soportada." +msgstr "No se admite la creación de gremios." #: ../src/net/tmwa/gui/guildtab.cpp:81 msgid "Guild name is missing." @@ -1770,7 +1757,7 @@ msgstr "Nombre no válido." #: ../src/main.cpp:173 msgid "Invalid server type, expected one of: tmwathena, manaserv" -msgstr "" +msgstr "Tipo de servidor no válido, esperado uno de: tmwathena, manaserv" #: ../src/net/manaserv/charhandler.cpp:172 msgid "Invalid slot number." @@ -1808,23 +1795,20 @@ msgid "Invite %s to join your party" msgstr "Invitar a %s para su grupo" #: ../src/net/manaserv/guildhandler.cpp:108 -#, fuzzy msgid "Invite failed." -msgstr "Fallo al sentarse!" +msgstr "La invitación ha fallado." #: ../src/net/manaserv/guildhandler.cpp:96 msgid "Invite sent." msgstr "Invitación enviada." #: ../src/net/manaserv/guildhandler.cpp:104 -#, fuzzy msgid "Invited player can't join another guild." -msgstr "Invitar a %s para unirse a tu clan" +msgstr "El jugador invitado no puede unirse a otro gremio." #: ../src/net/manaserv/guildhandler.cpp:100 -#, fuzzy msgid "Invited player is already in that guild." -msgstr "Invita al jugador %s para su clan %s." +msgstr "El jugador invitado ya está en ese gremio." #: ../src/gui/socialwindow.cpp:116 #, c-format @@ -1895,11 +1879,11 @@ msgstr "Trabajo: %d" #: ../src/net/manaserv/partyhandler.cpp:98 msgid "" "Joining party failed, because the invitation has timed out on the server." -msgstr "" +msgstr "No se pudo unir al grupo porque la invitación expiró en el servidor." #: ../src/net/manaserv/partyhandler.cpp:102 msgid "Joining party failed, because the inviter has left the game." -msgstr "" +msgstr "No se pudo unir al grupo porque el invitador abandonó el juego." #: ../src/gui/setup_joystick.cpp:40 msgid "Joystick" @@ -2269,15 +2253,14 @@ msgid "Notice" msgstr "Anuncio" #: ../src/gui/setup_audio.cpp:51 -#, fuzzy msgid "Notifications volume" -msgstr "Aviso de experiencia" +msgstr "Volumen delas notificaciones" #: ../src/gui/itemamountwindow.cpp:112 ../src/gui/okdialog.cpp:40 #: ../src/gui/quitdialog.cpp:46 ../src/gui/textdialog.cpp:39 #: ../src/gui/tradewindow.cpp:72 ../src/gui/tradewindow.cpp:74 msgid "OK" -msgstr "OK" +msgstr "De acuerdo" #: ../src/gui/customserverdialog.cpp:75 msgid "Ok" @@ -2294,25 +2277,24 @@ msgstr "Contrasena antigua incorrecta." #: ../src/gui/socialwindow.cpp:380 ../src/gui/socialwindow.cpp:676 #, c-format msgid "Online (%zu)" -msgstr "" +msgstr "Conectad@ (%zu)" #: ../src/gui/widgets/itemlinkhandler.cpp:66 #: ../src/gui/widgets/itemlinkhandler.cpp:95 msgid "Open URL Failed" -msgstr "" +msgstr "Error al abrir la URL" #: ../src/gui/widgets/itemlinkhandler.cpp:63 -#, fuzzy msgid "Open URL?" -msgstr "OpenGL" +msgstr "¿Abrir URL?" #: ../src/gui/setup_video.cpp:228 msgid "OpenGL (Legacy)" -msgstr "" +msgstr "OpenGL (heredado)" #: ../src/gui/widgets/itemlinkhandler.cpp:67 msgid "Opening of URLs requires SDL 2.0.14." -msgstr "" +msgstr "Para abrir URL se requiere SDL 2.0.14." #: ../src/commandhandler.h:31 #, c-format @@ -2456,9 +2438,9 @@ msgid "Play" msgstr "Jugar" #: ../src/net/manaserv/guildhandler.cpp:259 -#, fuzzy, c-format +#, c-format msgid "Player %s kicked you out of guild %s." -msgstr "%s te ha invitado al clan %s." +msgstr "El jugador %s te expulsó del gremio %s ." #: ../src/commandhandler.cpp:521 msgid "Player already ignored!" @@ -2512,9 +2494,8 @@ msgid "Please select a custom server." msgstr "Por favor selecione un servidor personalizado." #: ../src/gui/serverdialog.cpp:272 -#, fuzzy msgid "Please select a valid server." -msgstr "Por favor seleccione un servidor." +msgstr "Por favor seleccione un servidor válido." #: ../src/commandhandler.cpp:436 ../src/commandhandler.cpp:515 #: ../src/commandhandler.cpp:537 @@ -2522,9 +2503,8 @@ msgid "Please specify a name." msgstr "Por favor, especifique un nombre." #: ../src/gui/customserverdialog.cpp:167 -#, fuzzy msgid "Please type in at least the address of the server." -msgstr "Por favor tipee al menos ambos, la dirección y el puerto del servidor." +msgstr "Por favor, escriba al menos la dirección del servidor." #: ../src/net/tmwa/specialhandler.cpp:212 msgid "Poison had no effect..." @@ -2667,9 +2647,8 @@ msgid "Reset Windows" msgstr "Restaurar Ventanas" #: ../src/gui/setup_video.cpp:313 -#, fuzzy msgid "Resolution:" -msgstr "Relación" +msgstr "Resolución:" #: ../src/gui/inventorywindow.cpp:132 ../src/gui/popupmenu.cpp:389 msgid "Retrieve" @@ -2696,7 +2675,6 @@ msgid "Rotate the stick" msgstr "Gira el stick" #: ../src/gui/setup_audio.cpp:50 -#, fuzzy msgid "SFX volume" msgstr "Volumen Sfx" @@ -2711,24 +2689,24 @@ msgstr "Fallo al guardar screenshot!" #: ../src/gui/setup_video.cpp:315 msgid "Scale:" -msgstr "" +msgstr "Escala:" #: ../src/keyboardconfig.cpp:57 msgid "Screenshot" msgstr "Imprimir pantalla" #: ../src/game.cpp:328 -#, fuzzy, c-format +#, c-format msgid "Screenshot saved as %s" -msgstr "Screenshot guardada como" +msgstr "Captura de pantalla guardada como %s" #: ../src/keyboardconfig.cpp:100 msgid "Scroll Chat Down" -msgstr "Tirar el chat para abajo" +msgstr "Desplazarse hacia abajo en el chat" #: ../src/keyboardconfig.cpp:99 msgid "Scroll Chat Up" -msgstr "Tirar el chat para arriba" +msgstr "Desplazarse hacia arriba en el chat" #: ../src/gui/inventorywindow.cpp:87 msgid "Search:" @@ -3263,10 +3241,9 @@ msgid "This command tells you're away from keyboard with the given reason." msgstr "Este comando muestra que no estas en el PC por una razon dada." #: ../src/commandhandler.cpp:246 -#, fuzzy msgid "This command tries to make a tab for whispers between you and <nick>." msgstr "" -"Este comando crea una pestaña para mensajes privados con el jugador <nick>." +"Este comando intenta crear una pestaña para susurros entre usted y <nick>." #: ../src/gui/setup_colors.cpp:43 msgid "This is what the color looks like" @@ -3390,9 +3367,9 @@ msgid "Unable to equip." msgstr "Imposible equipar." #: ../src/net/tmwa/network.cpp:470 -#, fuzzy, c-format +#, c-format msgid "Unable to resolve host \"%s\"" -msgstr "No es posible determinar el host \"" +msgstr "No se puede resolver el host \" %s \"" #: ../src/net/tmwa/buysellhandler.cpp:124 msgid "Unable to sell." @@ -3419,6 +3396,8 @@ msgstr "Quitárselo antes" #, c-format msgid "Unhandled character select error message %i." msgstr "" +"Recibí un mensaje de error de carácter %i , que no es compatible con el " +"programa." #: ../src/net/tmwa/tradehandler.cpp:156 msgid "Unhandled trade cancel packet." @@ -3512,7 +3491,7 @@ msgstr "Usuario borrado permanentemente." #: ../src/gui/setup_video.cpp:227 msgid "VSync" -msgstr "" +msgstr "VSync" #: ../src/gui/setup_video.cpp:244 msgid "Video" @@ -3615,17 +3594,15 @@ msgstr "Suerte %+.1f" #: ../src/gui/setup_video.cpp:311 msgid "Window mode:" -msgstr "" +msgstr "Modo de la ventana:" #: ../src/gui/setup_video.cpp:221 -#, fuzzy msgid "Windowed" -msgstr "Ventana de ayuda" +msgstr "con ventanas" #: ../src/gui/setup_video.cpp:221 -#, fuzzy msgid "Windowed Fullscreen" -msgstr "Pantalla completa" +msgstr "Pantalla completa con ventana" #: ../src/net/manaserv/loginhandler.cpp:92 msgid "Wrong magic_token." @@ -3675,9 +3652,8 @@ msgid "You are not that alive anymore." msgstr "Ya no estás tan vivo..." #: ../src/net/tmwa/partyhandler.cpp:328 -#, fuzzy msgid "You can only invite when you are in a party!" -msgstr "Sólo puedes invitar cuando estés en un grupo!" +msgstr "¡Solo puedes invitar cuando estés en una fiesta!" #: ../src/net/tmwa/specialhandler.cpp:179 msgid "You cannot do that right now!" @@ -3814,7 +3790,7 @@ msgstr "Te han echado a patadas." #: ../src/net/tmwa/playerhandler.cpp:128 msgid "" "You've shuffled off your mortal coil, run down the curtain and joined the " -"bleedin' choir invisibile." +"bleedin' choir invisible." msgstr "" "Has dejado tu cuerpo mortal, bajado las cortinas y unido al sangriento coro " "de los invisibles." @@ -3837,7 +3813,7 @@ msgstr "" #: ../src/main.cpp:50 msgid "[mana-file] : The mana file is an XML file (.mana)" -msgstr "" +msgstr "[mana-file] : El archivo mana es un archivo XML (.mana)" #: ../src/gui/setup_interface.cpp:96 msgid "as particle" @@ -3741,7 +3741,7 @@ msgstr "" #: ../src/net/tmwa/playerhandler.cpp:128 msgid "" "You've shuffled off your mortal coil, run down the curtain and joined the " -"bleedin' choir invisibile." +"bleedin' choir invisible." msgstr "" #: ../src/net/tmwa/playerhandler.cpp:125 @@ -3762,7 +3762,7 @@ msgstr "" #: ../src/net/tmwa/playerhandler.cpp:128 msgid "" "You've shuffled off your mortal coil, run down the curtain and joined the " -"bleedin' choir invisibile." +"bleedin' choir invisible." msgstr "" #: ../src/net/tmwa/playerhandler.cpp:125 @@ -9,15 +9,15 @@ msgstr "" "Project-Id-Version: mana\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2024-10-23 09:58+0200\n" -"PO-Revision-Date: 2024-10-22 11:12+0000\n" -"Last-Translator: Allan Nordhøy <epost@anotheragency.no>\n" +"PO-Revision-Date: 2025-01-17 12:01+0000\n" +"Last-Translator: Ricky Tigg <ricky.tigg@gmail.com>\n" "Language-Team: Finnish <https://hosted.weblate.org/projects/mana/mana/fi/>\n" "Language: fi\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 5.8-rc\n" +"X-Generator: Weblate 5.10-dev\n" "X-Launchpad-Export-Date: 2010-03-05 19:28+0000\n" # TODO: internationalization: translating message fragments is nasty. @@ -206,14 +206,14 @@ msgid "%s is now a member of your party." msgstr "%s on nyt ryhmäsi jäsen." #: ../src/net/manaserv/partyhandler.cpp:129 -#, fuzzy, c-format +#, c-format msgid "%s joined the party on invitation from %s." -msgstr "Kieltäydyit pelaajan %s ryhmäkutsusta." +msgstr "%s liittyi juhliin %s:n kutsusta." #: ../src/net/manaserv/partyhandler.cpp:127 -#, fuzzy, c-format +#, c-format msgid "%s joined the party." -msgstr "%s liittyi ryhmään%s." +msgstr "%s liittyi juhliin." #: ../src/net/manaserv/chathandler.cpp:319 #, c-format @@ -1156,9 +1156,8 @@ msgid "Could not steal anything..." msgstr "Varastaminen ei onnistunut..." #: ../src/game.cpp:290 -#, fuzzy msgid "Could not take screenshot!" -msgstr "Ryhmän luonti epäonnistui." +msgstr "Kuvakaappausta ei voitu ottaa!" #: ../src/gui/charcreatedialog.cpp:85 ../src/gui/charselectdialog.cpp:393 #: ../src/gui/socialwindow.cpp:365 @@ -1833,9 +1832,8 @@ msgid "Invite %s to join your party" msgstr "Kutsu %s ryhmääsi" #: ../src/net/manaserv/guildhandler.cpp:108 -#, fuzzy msgid "Invite failed." -msgstr "Istuminen epäonnistui!" +msgstr "Kutsu epäonnistui." #: ../src/net/manaserv/guildhandler.cpp:96 msgid "Invite sent." @@ -1987,7 +1985,7 @@ msgstr "Taso: %d" # TODO: need translator comment. Optimistic translation: is this followed by channel listing? #: ../src/net/manaserv/chathandler.cpp:217 msgid "Listing channels." -msgstr "Kanavalistaus:" +msgstr "Kanavalistaus." #: ../src/resources/userpalette.cpp:104 msgid "Local Player Critical Hit" @@ -2507,7 +2505,7 @@ msgstr "Pelaajan huomiotta jättäminen epäonnistui!" # TODO: <swearing> #: ../src/commandhandler.cpp:552 msgid "Player could not be unignored!" -msgstr "Pelaajan uudelleenhuomiointi epäonnistui." +msgstr "Pelaajaa ei voitu jättää vailla huomiotta!" #: ../src/net/manaserv/charhandler.cpp:211 msgid "Player deleted." @@ -2515,11 +2513,11 @@ msgstr "Hahmo poistettu." #: ../src/commandhandler.cpp:550 msgid "Player no longer ignored!" -msgstr "Pelaaja huomioidaan taas." +msgstr "Pelaajaa ei enää jätetty huomiotta!" #: ../src/commandhandler.cpp:528 msgid "Player successfully ignored!" -msgstr "Pelaaja jää nyt huomiotta." +msgstr "Pelaaja onnistuneesti! jätetty huomioimatta!" # TODO: come up with a less kludgey translation for "ignore". Like sulkulista. #: ../src/commandhandler.cpp:545 @@ -2708,9 +2706,8 @@ msgid "Reset Windows" msgstr "Palauta ikkunoiden oletusasetukset" #: ../src/gui/setup_video.cpp:313 -#, fuzzy msgid "Resolution:" -msgstr "Relaatio" +msgstr "Resoluutio:" #: ../src/gui/inventorywindow.cpp:132 ../src/gui/popupmenu.cpp:389 msgid "Retrieve" @@ -2760,9 +2757,9 @@ msgid "Screenshot" msgstr "Kuvankaappaus" #: ../src/game.cpp:328 -#, fuzzy, c-format +#, c-format msgid "Screenshot saved as %s" -msgstr "Ruutukaappaus tallennettu nimellä " +msgstr "Kuvakaappaus tallennettu %s:lla" #: ../src/keyboardconfig.cpp:100 msgid "Scroll Chat Down" @@ -3439,9 +3436,9 @@ msgid "Unable to equip." msgstr "Käyttöönotto epäonnistui." #: ../src/net/tmwa/network.cpp:470 -#, fuzzy, c-format +#, c-format msgid "Unable to resolve host \"%s\"" -msgstr "Osoitetta ei löydy: \"" +msgstr "Isäntää \"%s\" ei voi selvittää" #: ../src/net/tmwa/buysellhandler.cpp:124 msgid "Unable to sell." @@ -3665,9 +3662,8 @@ msgid "Willpower %+.1f" msgstr "Tahdonvoima %+.1f" #: ../src/gui/setup_video.cpp:311 -#, fuzzy msgid "Window mode:" -msgstr " video tila: " +msgstr "Ikkunatila:" #: ../src/gui/setup_video.cpp:221 #, fuzzy @@ -3734,11 +3730,11 @@ msgstr "Voit kutsua ryhmään vain kun olet siinä itse!" #: ../src/net/tmwa/specialhandler.cpp:179 msgid "You cannot do that right now!" -msgstr "Et voi tehdä tätä juuri nyt." +msgstr "Et voi tehdä tätä juuri nyt!" #: ../src/net/tmwa/specialhandler.cpp:185 msgid "You cannot use this skill with that kind of weapon!" -msgstr "Et voi käyttää tätä taitoa tuollaisen aseen kanssa." +msgstr "Et voi käyttää tätä taitoa tuollaisen aseen kanssa!" #: ../src/gui/tradewindow.cpp:303 msgid "You don't have enough money." @@ -3788,7 +3784,7 @@ msgstr "Erosit ryhmästä." #: ../src/net/tmwa/specialhandler.cpp:176 msgid "You have no memos!" -msgstr "Sinulla ei ole muistioita (memo)." +msgstr "Sinulla ei ole muistioita (memo)!" #: ../src/net/tmwa/specialhandler.cpp:167 msgid "You have not yet reached a high enough lvl!" @@ -3806,11 +3802,11 @@ msgstr "Käynnistä ohjelma uudelleen, jotta muutos astuu voimaan." #: ../src/net/tmwa/specialhandler.cpp:191 msgid "You need another blue gem!" -msgstr "Tarvitset toisen sinisen helmen." +msgstr "Tarvitset toisen sinisen helmen!" #: ../src/net/tmwa/specialhandler.cpp:188 msgid "You need another red gem!" -msgstr "Tarvitset toisen punaisen helmen." +msgstr "Tarvitset toisen punaisen helmen!" #: ../src/gui/logindialog.cpp:119 msgid "You need to use the website to register an account for this server." @@ -3823,15 +3819,15 @@ msgstr "" #, c-format msgid "You picked up %d [@@%d|%s@@]." msgid_plural "You picked up %d [@@%d|%s@@]." -msgstr[0] "[@@%2$d|%3$s@@] (%1$d kpl) otettu." -msgstr[1] "[@@%2$d|%3$s@@] (%1$d kpl) otettu." +msgstr[0] "Poimit %d [@@%d|%s@@]." +msgstr[1] "Poimit %d [@@%d|%s@@]." #: ../src/net/tmwa/playerhandler.cpp:326 #, c-format msgid "You picked up %s." msgstr "%s noukittu." -# Leisure Suit Larry reference. +# Leisure Suit Larry reference. #: ../src/net/manaserv/beinghandler.cpp:293 #: ../src/net/tmwa/playerhandler.cpp:115 msgid "" @@ -3876,7 +3872,7 @@ msgstr "Potkaisit tyhjää." #: ../src/net/tmwa/playerhandler.cpp:128 msgid "" "You've shuffled off your mortal coil, run down the curtain and joined the " -"bleedin' choir invisibile." +"bleedin' choir invisible." msgstr "" "Olet heittänyt henkesi, poistunut keskuudestamme ja loikannut Tuonelan " "jokeen." @@ -3880,7 +3880,7 @@ msgstr "Tu viens de toucher le fond." #: ../src/net/tmwa/playerhandler.cpp:128 msgid "" "You've shuffled off your mortal coil, run down the curtain and joined the " -"bleedin' choir invisibile." +"bleedin' choir invisible." msgstr "" "Vous êtes sorti de votre enveloppe charnelle et mortelle. Vous avez rejoint " "l'armée de l'ombre." @@ -3963,7 +3963,7 @@ msgstr "חדלת מלהתקיים." #: ../src/net/tmwa/playerhandler.cpp:128 msgid "" "You've shuffled off your mortal coil, run down the curtain and joined the " -"bleedin' choir invisibile." +"bleedin' choir invisible." msgstr "התפוגגת ועברת לפגוש את הבורא." #: ../src/net/tmwa/playerhandler.cpp:125 @@ -3954,7 +3954,7 @@ msgstr "Vi ste šutirali sić." #: ../src/net/tmwa/playerhandler.cpp:128 msgid "" "You've shuffled off your mortal coil, run down the curtain and joined the " -"bleedin' choir invisibile." +"bleedin' choir invisible." msgstr "" #: ../src/net/tmwa/playerhandler.cpp:125 @@ -3981,7 +3981,7 @@ msgstr "Feldobtad a talpad." #: ../src/net/tmwa/playerhandler.cpp:128 msgid "" "You've shuffled off your mortal coil, run down the curtain and joined the " -"bleedin' choir invisibile." +"bleedin' choir invisible." msgstr "Megfulladtál a saját véredben." #: ../src/net/tmwa/playerhandler.cpp:125 @@ -3792,7 +3792,7 @@ msgstr "" #: ../src/net/tmwa/playerhandler.cpp:128 msgid "" "You've shuffled off your mortal coil, run down the curtain and joined the " -"bleedin' choir invisibile." +"bleedin' choir invisible." msgstr "" #: ../src/net/tmwa/playerhandler.cpp:125 @@ -3979,7 +3979,7 @@ msgstr "Hai tirato le cuoia." #: ../src/net/tmwa/playerhandler.cpp:128 msgid "" "You've shuffled off your mortal coil, run down the curtain and joined the " -"bleedin' choir invisibile." +"bleedin' choir invisible." msgstr "" #: ../src/net/tmwa/playerhandler.cpp:125 @@ -3987,7 +3987,7 @@ msgstr "人間界から追い出された。" #: ../src/net/tmwa/playerhandler.cpp:128 msgid "" "You've shuffled off your mortal coil, run down the curtain and joined the " -"bleedin' choir invisibile." +"bleedin' choir invisible." msgstr "最後の呼吸だった。死神に会った後、無と結合しちゃった。" #: ../src/net/tmwa/playerhandler.cpp:125 @@ -8,16 +8,16 @@ msgstr "" "Project-Id-Version: mana\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2024-10-23 09:58+0200\n" -"PO-Revision-Date: 2009-07-23 22:14+0000\n" -"Last-Translator: Mpa4Hu <ymen9@pisem.net>\n" -"Language-Team: Georgian <ka@li.org>\n" +"PO-Revision-Date: 2025-02-11 05:01+0000\n" +"Last-Translator: Temuri Doghonadze <temuri.doghonadze@gmail.com>\n" +"Language-Team: Georgian <https://hosted.weblate.org/projects/mana/mana/ka/>\n" "Language: ka\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Weblate 5.10-dev\n" "X-Launchpad-Export-Date: 2010-03-05 19:28+0000\n" -"X-Generator: Launchpad (build Unknown)\n" #: ../src/main.cpp:52 msgid " to the mana client." @@ -72,9 +72,8 @@ msgid " -d --data : Directory to load game data from" msgstr "" #: ../src/main.cpp:56 -#, fuzzy msgid " -h --help : Display this help" -msgstr "/help > დახმარების გამოტანა" +msgstr " -h --help : ამ დახმარების გამოტანა" #: ../src/main.cpp:62 msgid " -p --port : Login server port" @@ -3052,9 +3051,8 @@ msgid "This account is already logged in." msgstr "" #: ../src/net/tmwa/gui/guildtab.cpp:73 -#, fuzzy msgid "This command causes the player to leave the guild." -msgstr "ამ კომანდას გამოაქ კონკრეტული რუქის სახელი" +msgstr "ეს ბრძანება აიძულებს მომთამაშეს, გილდიიდან გავიდეს." #: ../src/net/tmwa/gui/partytab.cpp:74 msgid "This command causes the player to leave the party." @@ -3069,9 +3067,8 @@ msgid "This command changes the party's item sharing policy." msgstr "" #: ../src/commandhandler.cpp:255 -#, fuzzy msgid "This command clears the away status and message." -msgstr "ამ კომანდას გამოაქ კონკრეტული რუქის სახელი" +msgstr "ეს ბრძანება გაასუფთავებს გასულობის სტატუსს და შეტყობინებას." #: ../src/commandhandler.cpp:209 msgid "This command clears the chat log of previous chat." @@ -3095,7 +3092,7 @@ msgstr "" #: ../src/commandhandler.cpp:304 msgid "This command displays the name of the current map." -msgstr "ამ კომანდას გამოაქ კონკრეტული რუქის სახელი" +msgstr "ეს ბრძანება მიმდინარე რუკის სახელს აჩვენებს." #: ../src/commandhandler.cpp:309 msgid "This command displays the number of players currently online." @@ -3124,14 +3121,16 @@ msgid "" msgstr "" #: ../src/commandhandler.cpp:214 -#, fuzzy msgid "This command ignores the given player regardless of current relations." -msgstr "ამ კომანდას გამოაქ კონკრეტული რუქის სახელი" +msgstr "" +"ეს ბრძანება გამოტოვებს მითითებულ მოთამაშეს მიმდინარე ურთიერთობების " +"გაუთვალისწინებლად." #: ../src/gui/widgets/whispertab.cpp:89 -#, fuzzy msgid "This command ignores the other player regardless of current relations." -msgstr "ამ კომანდას გამოაქ კონკრეტული რუქის სახელი" +msgstr "" +"ეს ბრძანება გამოტოვებს სხვა მოთამაშეს მიმდინარე ურთიერთობების " +"გაუთვალისწინებად." #: ../src/commandhandler.cpp:265 ../src/net/tmwa/gui/partytab.cpp:67 msgid "This command invites <nick> to party with you." @@ -3387,9 +3386,9 @@ msgid "Unknown connection error." msgstr "" #: ../src/net/manaserv/charhandler.cpp:226 -#, fuzzy, c-format +#, c-format msgid "Unknown error (%d)." -msgstr "უცნობი კომანდა." +msgstr "უცნობი შეცდომა (%d)." #: ../src/net/manaserv/charhandler.cpp:175 #: ../src/net/manaserv/loginhandler.cpp:101 @@ -3745,7 +3744,7 @@ msgstr "" #: ../src/net/tmwa/playerhandler.cpp:128 msgid "" "You've shuffled off your mortal coil, run down the curtain and joined the " -"bleedin' choir invisibile." +"bleedin' choir invisible." msgstr "" #: ../src/net/tmwa/playerhandler.cpp:125 diff --git a/po/mana.pot b/po/mana.pot index 36dccdab..56865cc0 100644 --- a/po/mana.pot +++ b/po/mana.pot @@ -3502,7 +3502,7 @@ msgstr "" #: ../src/net/tmwa/playerhandler.cpp:128 msgid "" "You've shuffled off your mortal coil, run down the curtain and joined the " -"bleedin' choir invisibile." +"bleedin' choir invisible." msgstr "" #: ../src/net/tmwa/playerhandler.cpp:130 @@ -3851,7 +3851,7 @@ msgstr "" #: ../src/net/tmwa/playerhandler.cpp:128 msgid "" "You've shuffled off your mortal coil, run down the curtain and joined the " -"bleedin' choir invisibile." +"bleedin' choir invisible." msgstr "" #: ../src/net/tmwa/playerhandler.cpp:125 @@ -3772,7 +3772,7 @@ msgstr "" #: ../src/net/tmwa/playerhandler.cpp:128 msgid "" "You've shuffled off your mortal coil, run down the curtain and joined the " -"bleedin' choir invisibile." +"bleedin' choir invisible." msgstr "" #: ../src/net/tmwa/playerhandler.cpp:125 @@ -3987,7 +3987,7 @@ msgstr "" #: ../src/net/tmwa/playerhandler.cpp:128 msgid "" "You've shuffled off your mortal coil, run down the curtain and joined the " -"bleedin' choir invisibile." +"bleedin' choir invisible." msgstr "" #: ../src/net/tmwa/playerhandler.cpp:125 @@ -9,8 +9,8 @@ msgstr "" "Project-Id-Version: Mana\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2024-10-23 09:58+0200\n" -"PO-Revision-Date: 2024-10-22 11:12+0000\n" -"Last-Translator: Allan Nordhøy <epost@anotheragency.no>\n" +"PO-Revision-Date: 2024-10-24 09:16+0000\n" +"Last-Translator: Eryk Michalak <gnu.ewm@protonmail.com>\n" "Language-Team: Polish <https://hosted.weblate.org/projects/mana/mana/pl/>\n" "Language: pl\n" "MIME-Version: 1.0\n" @@ -18,7 +18,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " "|| n%100>=20) ? 1 : 2);\n" -"X-Generator: Weblate 5.8-rc\n" +"X-Generator: Weblate 5.8.2-dev\n" #: ../src/main.cpp:52 msgid " to the mana client." @@ -137,7 +137,7 @@ msgstr "%d FPS (OpenGL)" #: ../src/gui/setup_video.cpp:178 #, c-format msgid "%dx" -msgstr "" +msgstr "%dx" #: ../src/client.cpp:1074 ../src/client.cpp:1097 #, c-format @@ -205,9 +205,9 @@ msgid "%s joined the party on invitation from %s." msgstr "Odrzucono zaproszenie do grupy od %s." #: ../src/net/manaserv/partyhandler.cpp:127 -#, fuzzy, c-format +#, c-format msgid "%s joined the party." -msgstr "%s przyłączył/a się do grupy %s." +msgstr "%s dołączył/a do imprezy." #: ../src/net/manaserv/chathandler.cpp:319 #, c-format @@ -670,7 +670,7 @@ msgstr "Błąd uwierzytelniania." #: ../src/gui/setup_video.cpp:176 #, c-format msgid "Auto (%dx)" -msgstr "" +msgstr "Automatyczne (%dx)" #: ../src/localplayer.cpp:1023 msgid "Away" @@ -1141,9 +1141,8 @@ msgid "Could not steal anything..." msgstr "Nie udało się niczego ukraść..." #: ../src/game.cpp:290 -#, fuzzy msgid "Could not take screenshot!" -msgstr "Nie udało się utworzyć grupy." +msgstr "Nie udało się wykonać zrzutu ekranu!" #: ../src/gui/charcreatedialog.cpp:85 ../src/gui/charselectdialog.cpp:393 #: ../src/gui/socialwindow.cpp:365 @@ -1190,9 +1189,8 @@ msgid "Cursor: (%d, %d)" msgstr "Kursor: (%d, %d)" #: ../src/gui/setup_video.cpp:102 -#, fuzzy msgid "Custom" -msgstr "Ręcznie dodany serwer" +msgstr "Niestandardowe" #: ../src/gui/customserverdialog.cpp:50 msgid "Custom Server" @@ -1483,9 +1481,8 @@ msgstr "" "rodzaj przedmiotu w okienku." #: ../src/gui/setup_video.cpp:374 -#, fuzzy msgid "Failed to change video mode." -msgstr "Nie można użyć przedmiotu." +msgstr "Nie udało się zmienić trybu obrazu." #: ../src/net/tmwa/charserverhandler.cpp:136 msgid "Failed to create character. Most likely the name is already taken." @@ -1540,7 +1537,6 @@ msgid "Friend" msgstr "Przyjaciel" #: ../src/gui/setup_video.cpp:221 -#, fuzzy msgid "Fullscreen" msgstr "Pełny ekran" @@ -1553,9 +1549,8 @@ msgid "GUI debug" msgstr "" #: ../src/gui/setup_interface.cpp:112 -#, fuzzy msgid "GUI opacity" -msgstr "Przezroczystość GUI" +msgstr "Przezroczystość interfejsu" #: ../src/net/tmwa/gamehandler.cpp:89 msgid "Game" @@ -1613,9 +1608,8 @@ msgid "Guild created." msgstr "Gildia została utworzona." #: ../src/net/tmwa/guildhandler.cpp:63 -#, fuzzy msgid "Guild creation isn't supported." -msgstr "Tworzenie gildii nie jest jeszcze wspierane przez ten serwer." +msgstr "Tworzenie gildii nie jest jeszcze wspierane." #: ../src/net/tmwa/gui/guildtab.cpp:81 msgid "Guild name is missing." @@ -2278,9 +2272,8 @@ msgid "Notice" msgstr "Powiadomienie" #: ../src/gui/setup_audio.cpp:51 -#, fuzzy msgid "Notifications volume" -msgstr "Powiadomienie o Exp" +msgstr "Głośność powiadomień" #: ../src/gui/itemamountwindow.cpp:112 ../src/gui/okdialog.cpp:40 #: ../src/gui/quitdialog.cpp:46 ../src/gui/textdialog.cpp:39 @@ -2303,21 +2296,20 @@ msgstr "Stare hasło nieprawidłowe." #: ../src/gui/socialwindow.cpp:380 ../src/gui/socialwindow.cpp:676 #, c-format msgid "Online (%zu)" -msgstr "" +msgstr "Online (%zu)" #: ../src/gui/widgets/itemlinkhandler.cpp:66 #: ../src/gui/widgets/itemlinkhandler.cpp:95 msgid "Open URL Failed" -msgstr "" +msgstr "Nie udało się otworzyć adresu URL" #: ../src/gui/widgets/itemlinkhandler.cpp:63 -#, fuzzy msgid "Open URL?" -msgstr "OpenGL" +msgstr "Otworzyć ten adres URL?" #: ../src/gui/setup_video.cpp:228 msgid "OpenGL (Legacy)" -msgstr "" +msgstr "OpenGL (przestarzałe)" #: ../src/gui/widgets/itemlinkhandler.cpp:67 msgid "Opening of URLs requires SDL 2.0.14." @@ -2520,9 +2512,8 @@ msgid "Please select a custom server." msgstr "Proszę wybrać ręcznie dodany serwer." #: ../src/gui/serverdialog.cpp:272 -#, fuzzy msgid "Please select a valid server." -msgstr "Proszę wybrać serwer." +msgstr "Proszę wybrać prawidłowy serwer." #: ../src/commandhandler.cpp:436 ../src/commandhandler.cpp:515 #: ../src/commandhandler.cpp:537 @@ -2675,9 +2666,8 @@ msgid "Reset Windows" msgstr "Zresetuj okna" #: ../src/gui/setup_video.cpp:313 -#, fuzzy msgid "Resolution:" -msgstr "Relacja" +msgstr "Rozdzielczość:" #: ../src/gui/inventorywindow.cpp:132 ../src/gui/popupmenu.cpp:389 msgid "Retrieve" @@ -2704,7 +2694,6 @@ msgid "Rotate the stick" msgstr "Obróć drążek" #: ../src/gui/setup_audio.cpp:50 -#, fuzzy msgid "SFX volume" msgstr "Głośność efektów dźwiękowych" @@ -2719,16 +2708,16 @@ msgstr "Zapisywanie zrzutu ekranu nie powiodło się!" #: ../src/gui/setup_video.cpp:315 msgid "Scale:" -msgstr "" +msgstr "Skala:" #: ../src/keyboardconfig.cpp:57 msgid "Screenshot" msgstr "Zrzut ekranu" #: ../src/game.cpp:328 -#, fuzzy, c-format +#, c-format msgid "Screenshot saved as %s" -msgstr "Zrzut ekranu zapisany jako" +msgstr "Zapisano zrzut ekranu jako %s" #: ../src/keyboardconfig.cpp:100 msgid "Scroll Chat Down" @@ -3401,9 +3390,9 @@ msgid "Unable to equip." msgstr "Nie można założyć." #: ../src/net/tmwa/network.cpp:470 -#, fuzzy, c-format +#, c-format msgid "Unable to resolve host \"%s\"" -msgstr "Nie można było odnaleźć serwera." +msgstr "Nie można odnaleźć hosta \"%s\" ." #: ../src/net/tmwa/buysellhandler.cpp:124 msgid "Unable to sell." @@ -3523,7 +3512,7 @@ msgstr "Login pernamentnie usunięty." #: ../src/gui/setup_video.cpp:227 msgid "VSync" -msgstr "" +msgstr "Synchronizacja pionowa" #: ../src/gui/setup_video.cpp:244 msgid "Video" @@ -3626,17 +3615,15 @@ msgstr "Siła woli %+.1f" #: ../src/gui/setup_video.cpp:311 msgid "Window mode:" -msgstr "" +msgstr "Tryb okna:" #: ../src/gui/setup_video.cpp:221 -#, fuzzy msgid "Windowed" -msgstr "Okno Pomocy" +msgstr "W oknie" #: ../src/gui/setup_video.cpp:221 -#, fuzzy msgid "Windowed Fullscreen" -msgstr "Pełny ekran" +msgstr "Pełny ekran w oknie" #: ../src/net/manaserv/loginhandler.cpp:92 msgid "Wrong magic_token." @@ -3827,7 +3814,7 @@ msgstr "Kopnąłeś w kalendarz." #: ../src/net/tmwa/playerhandler.cpp:128 msgid "" "You've shuffled off your mortal coil, run down the curtain and joined the " -"bleedin' choir invisibile." +"bleedin' choir invisible." msgstr "" "Zrzuciłeś swą ziemską powłokę, wyniosłeś ducha poza doczesne wymiary i " "przyłączyłeś się do chórów anielskich." @@ -8,109 +8,96 @@ msgstr "" "Project-Id-Version: mana\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2024-10-23 09:58+0200\n" -"PO-Revision-Date: 2024-10-22 11:12+0000\n" -"Last-Translator: Allan Nordhøy <epost@anotheragency.no>\n" -"Language-Team: Portuguese <https://hosted.weblate.org/projects/mana/mana/pt/" -">\n" +"PO-Revision-Date: 2024-11-26 02:03+0000\n" +"Last-Translator: Antônio Silva Neto <ntsneto@gmail.com>\n" +"Language-Team: Portuguese <https://hosted.weblate.org/projects/mana/mana/pt/>" +"\n" "Language: pt\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 5.8-rc\n" +"X-Generator: Weblate 5.9-dev\n" "X-Launchpad-Export-Date: 2010-03-05 19:28+0000\n" #: ../src/main.cpp:52 msgid " to the mana client." -msgstr "" +msgstr " para o cliente mana." #: ../src/main.cpp:51 msgid " used to set custom parameters" -msgstr "" +msgstr " usado para definir parâmetros personalizados" #: ../src/main.cpp:70 -#, fuzzy msgid " --chat-log-dir : Chat log dir to use" -msgstr " -C --config-file : Ficheiro de configuração a ser usado" +msgstr " --chat-log-dir : Diretório a ser usado para logs de chat" #: ../src/main.cpp:69 -#, fuzzy msgid " --localdata-dir : Directory to use as local data directory" -msgstr " -S --home-dir : Directório a ser usado como pasta inicial" +msgstr " --localdata-dir : Diretório a ser usado como pasta inicial" #: ../src/main.cpp:73 -#, fuzzy msgid " --no-opengl : Disable OpenGL for this session" -msgstr " -O --no-opengl : Desabilita OpenGL nesta sessão" +msgstr " --no-opengl : Desabilita OpenGL nesta sessão" #: ../src/main.cpp:71 -#, fuzzy msgid " --screenshot-dir : Directory to store screenshots" -msgstr " -S --home-dir : Directório a ser usado como pasta inicial" +msgstr " --screenshot-dir : Pasta a ser usada para salvar captura de telas" #: ../src/main.cpp:64 -#, fuzzy msgid " --update-host : Use this update host" -msgstr " -H --update-host : Usa esta actualização do host" +msgstr " --update-host : Use este host de atualização" #: ../src/main.cpp:57 -#, fuzzy msgid " -C --config-dir : Configuration directory to use" -msgstr " -C --config-file : Ficheiro de configuração a ser usado" +msgstr " -C --config-dir : Pasta de configuração a ser utilizada" #: ../src/main.cpp:65 msgid " -D --default : Choose default character server and character" msgstr "" +" -D --default : Escolher o servidor de personagens padrão e " +"personagem" #: ../src/main.cpp:59 -#, fuzzy msgid " -P --password : Login with this password" -msgstr " -P --password : Efectua login com esta senha" +msgstr " -P --password : Fazer login com esta senha" #: ../src/main.cpp:58 -#, fuzzy msgid " -U --username : Login with this username" -msgstr " -U --username : Efectua login com este utilizador" +msgstr " -U --username : Fazer login com este nome de usuário" #: ../src/main.cpp:60 -#, fuzzy msgid " -c --character : Login with this character" -msgstr " -c --character : Efectua login com este personagem" +msgstr " -c --character : Fazer login com este personagem" #: ../src/main.cpp:68 -#, fuzzy msgid " -d --data : Directory to load game data from" -msgstr " -d --data : Pasta de onde os dados do jogo vão ser carregados" +msgstr "" +" -d --data : Pasta de onde os dados do jogo vão ser carregados" #: ../src/main.cpp:56 -#, fuzzy msgid " -h --help : Display this help" -msgstr " -h --help : Exibe esta ajuda" +msgstr " -h --help : Exibe esta ajuda" #: ../src/main.cpp:62 -#, fuzzy msgid " -p --port : Login server port" -msgstr " -p --port : Porta do servidor de login" +msgstr " -p --port : Porta do servidor de login" #: ../src/main.cpp:61 -#, fuzzy msgid " -s --server : Login server name or IP" -msgstr " -s --server : Nome ou IP do servidor de login" +msgstr " -s --server : Nome ou IP do servidor de login" #: ../src/main.cpp:67 -#, fuzzy msgid " -u --skip-update : Skip the update downloads" -msgstr " -u --skip-update : Não faz downloads de actualização" +msgstr " -u --skip-update : Pular os downloads de atualização" #: ../src/main.cpp:55 -#, fuzzy msgid " -v --version : Display the version" -msgstr " -v --version : Exibe a versão" +msgstr " -v --version : Exibe a versão" #: ../src/main.cpp:63 -#, fuzzy msgid " -y --server-type : Login server type" -msgstr " -s --server : Nome ou IP do servidor de login" +msgstr " -y --server-type : Tipo de servidor de login" #: ../src/gui/updaterwindow.cpp:410 msgid "##1 It is strongly recommended that" @@ -121,49 +108,48 @@ msgid "##1 The update process is incomplete." msgstr "##1 O processo de update está incompleto." #: ../src/gui/updaterwindow.cpp:412 -#, fuzzy msgid "##1 you try again later." -msgstr "##1 você tente novamente mais tarde" +msgstr "##1 Tente novamente mais tarde." #: ../src/net/tmwa/generalhandler.cpp:243 -#, fuzzy, no-c-format +#, no-c-format msgid "% Accuracy" -msgstr "% Precisão:" +msgstr "% Precisão" #: ../src/net/tmwa/generalhandler.cpp:247 -#, fuzzy, no-c-format +#, no-c-format msgid "% Critical" -msgstr "Golpe crítico" +msgstr "% Crítico" #: ../src/net/tmwa/generalhandler.cpp:245 -#, fuzzy, no-c-format +#, no-c-format msgid "% Evade" -msgstr "% Fuga:" +msgstr "% Evasão" #: ../src/gui/debugwindow.cpp:60 #, c-format msgid "%d FPS" -msgstr "" +msgstr "%d FPS" #: ../src/gui/debugwindow.cpp:55 #, c-format msgid "%d FPS (OpenGL)" -msgstr "" +msgstr "%d FPS (OpenGL)" #: ../src/gui/setup_video.cpp:178 #, c-format msgid "%dx" -msgstr "" +msgstr "%dx" #: ../src/client.cpp:1074 ../src/client.cpp:1097 #, c-format msgid "%s doesn't exist and can't be created! Exiting." -msgstr "" +msgstr "%s não existe e não pode ser criado! Saindo." #: ../src/net/manaserv/chathandler.cpp:314 -#, fuzzy, c-format +#, c-format msgid "%s entered the channel." -msgstr "%s entrou para o grupo." +msgstr "%s entrou no canal." #: ../src/gui/socialwindow.cpp:643 #, c-format @@ -171,9 +157,9 @@ msgid "%s has invited you to join the %s party." msgstr "%s te convidou para entrar no grupo %s." #: ../src/gui/socialwindow.cpp:600 -#, fuzzy, c-format +#, c-format msgid "%s has invited you to join the guild %s." -msgstr "%s te convidou para entrar no grupo %s." +msgstr "%s te convidou para entrar na guilda %s." #: ../src/gui/socialwindow.cpp:638 #, c-format @@ -183,7 +169,7 @@ msgstr "%s te convidou para entrar no seu grupo." #: ../src/net/manaserv/chathandler.cpp:345 #, c-format msgid "%s has kicked %s." -msgstr "" +msgstr "%s expulsou %s." #: ../src/net/tmwa/partyhandler.cpp:234 #, c-format @@ -193,7 +179,7 @@ msgstr "%s saiu do seu grupo." #: ../src/net/manaserv/chathandler.cpp:335 #, c-format msgid "%s has set mode %s on user %s." -msgstr "" +msgstr "%s definiu o modo %s para o usuário %s." #: ../src/net/tmwa/partyhandler.cpp:119 #, c-format @@ -201,9 +187,9 @@ msgid "%s is already a member of a party." msgstr "%s já é membro de um grupo." #: ../src/net/manaserv/partyhandler.cpp:160 -#, fuzzy, c-format +#, c-format msgid "%s is already in a party." -msgstr "%s já é membro de um grupo." +msgstr "%s já está em um grupo." #: ../src/net/tmwa/partyhandler.cpp:356 #, c-format @@ -216,19 +202,19 @@ msgid "%s is now a member of your party." msgstr "%s agora é um membro do seu grupo." #: ../src/net/manaserv/partyhandler.cpp:129 -#, fuzzy, c-format +#, c-format msgid "%s joined the party on invitation from %s." -msgstr "Rejeitar convite de %s." +msgstr "%s Juntou-se ao grupo a convite de %s." #: ../src/net/manaserv/partyhandler.cpp:127 -#, fuzzy, c-format +#, c-format msgid "%s joined the party." -msgstr "%s entrou para o grupo." +msgstr "%s entrou no grupo." #: ../src/net/manaserv/chathandler.cpp:319 #, c-format msgid "%s left the channel." -msgstr "" +msgstr "%s saiu do canal." #: ../src/net/tmwa/partyhandler.cpp:123 #, c-format @@ -236,9 +222,9 @@ msgid "%s refused your invitation." msgstr "%s recusou seu convite." #: ../src/net/manaserv/partyhandler.cpp:151 -#, fuzzy, c-format +#, c-format msgid "%s rejected your invite." -msgstr "%s recusou seu convite." +msgstr "%s rejeitou o seu convite." #: ../src/net/manaserv/tradehandler.cpp:116 #: ../src/net/tmwa/tradehandler.cpp:110 @@ -247,25 +233,25 @@ msgid "%s wants to trade with you, do you accept?" msgstr "%s quer negociar com você, você aceita?" #: ../src/gui/widgets/chattab.cpp:186 -#, fuzzy, c-format +#, c-format msgid "%s whispers: %s" -msgstr "%s sussurou: " +msgstr "%s sussurrou: %s" #: ../src/gui/charselectdialog.cpp:395 ../src/gui/charselectdialog.cpp:396 msgid "(empty)" -msgstr "" +msgstr "(vazio)" #: ../src/gui/buydialog.cpp:73 ../src/gui/itemamountwindow.cpp:111 #: ../src/gui/npcdialog.cpp:122 ../src/gui/selldialog.cpp:75 #: ../src/gui/statuswindow.cpp:467 msgid "+" -msgstr "" +msgstr "+" #: ../src/gui/buydialog.cpp:76 ../src/gui/itemamountwindow.cpp:110 #: ../src/gui/npcdialog.cpp:123 ../src/gui/selldialog.cpp:76 #: ../src/gui/statuswindow.cpp:477 msgid "-" -msgstr "" +msgstr "-" #: ../src/commandhandler.cpp:152 msgid "-- Help --" @@ -273,7 +259,7 @@ msgstr "-- Ajuda --" #: ../src/commandhandler.cpp:171 msgid "/away > Tell the other whispering players you're away from keyboard." -msgstr "" +msgstr "/away > Avise os outros jogadores que você está longe do teclado." #: ../src/commandhandler.cpp:162 msgid "/clear > Clears this window" @@ -284,9 +270,8 @@ msgid "/close > Close the whisper tab" msgstr "/close > Fecha a aba de sussurros" #: ../src/commandhandler.cpp:180 -#, fuzzy msgid "/createparty > Create a new party" -msgstr "/create > Cria um novo grupo" +msgstr "/createparty > Criar um novo grupo" #: ../src/net/tmwa/gui/partytab.cpp:57 msgid "/exp > Show/change party experience sharing options" @@ -302,16 +287,15 @@ msgstr "/help > Exibe esta ajuda." #: ../src/gui/widgets/whispertab.cpp:71 msgid "/ignore > Ignore the other player" -msgstr "" +msgstr "/ignore > Ignorar o jogador" #: ../src/commandhandler.cpp:174 msgid "/ignore > ignore a player" -msgstr "" +msgstr "/ignore > ignorar um jogador" #: ../src/net/tmwa/gui/guildtab.cpp:54 -#, fuzzy msgid "/invite > Invite a player to your guild" -msgstr "/invite > Convida um jogador para o seu grupo" +msgstr "/invite > Convida um jogador para a sua guilda" #: ../src/net/tmwa/gui/partytab.cpp:53 msgid "/invite > Invite a player to your party" @@ -330,19 +314,16 @@ msgid "/kick > Kick a user from the channel" msgstr "/kick > Expulsa um utilizador do canal" #: ../src/net/tmwa/gui/guildtab.cpp:56 -#, fuzzy msgid "/kick > Kick someone from the guild you are in" -msgstr "/kick > Expulsa alguém do grupo em que você está" +msgstr "/kick > Expulsa alguém da guilda em que você está" #: ../src/net/tmwa/gui/partytab.cpp:55 -#, fuzzy msgid "/kick > Kick someone from the party you are in" msgstr "/kick > Expulsa alguém do grupo em que você está" #: ../src/net/tmwa/gui/guildtab.cpp:55 -#, fuzzy msgid "/leave > Leave the guild you are in" -msgstr "/leave > Sai do grupo em que você está" +msgstr "/leave > Sai da guilda em que você está" #: ../src/net/tmwa/gui/partytab.cpp:54 msgid "/leave > Leave the party you are in" @@ -400,11 +381,11 @@ msgstr "/topic > Definir o tópico deste canal" #: ../src/gui/widgets/whispertab.cpp:72 msgid "/unignore > Stop ignoring the other player" -msgstr "" +msgstr "/unignore > Deixar de ignorar o jogador" #: ../src/commandhandler.cpp:175 msgid "/unignore > stop ignoring a player" -msgstr "" +msgstr "/unignore > deixar de ignorar um jogador" #: ../src/gui/widgets/channeltab.cpp:48 msgid "/users > Lists the users in the current channel" @@ -428,7 +409,7 @@ msgstr "/who > Mostra o numero de utilizadores online" #: ../src/gui/outfitwindow.cpp:49 msgid "<" -msgstr "" +msgstr "<" #: ../src/net/tmwa/gui/partytab.cpp:90 msgid "" @@ -456,30 +437,28 @@ msgstr "" #: ../src/gui/outfitwindow.cpp:50 msgid ">" -msgstr "" +msgstr ">" #: ../src/gui/setup_interface.cpp:61 ../src/gui/setup_players.cpp:198 msgid "???" msgstr "???" #: ../src/gui/socialwindow.cpp:605 -#, fuzzy msgid "Accept Guild Invite" -msgstr "Aceitar convite para o grupo" +msgstr "Aceitar convite para a guilda" #: ../src/gui/socialwindow.cpp:651 msgid "Accept Party Invite" msgstr "Aceitar convite para o grupo" #: ../src/gui/socialwindow.cpp:504 -#, fuzzy msgid "Accepted guild invite" -msgstr "Aceitar convite para o grupo" +msgstr "Convite para a guilda aceito" #: ../src/gui/socialwindow.cpp:485 -#, fuzzy, c-format +#, c-format msgid "Accepted party invite from %s." -msgstr "Acaitar convite de %s." +msgstr "Convite de %s para o grupo foi aceito." #: ../src/game.cpp:713 msgid "Accepting incoming trade requests" @@ -491,26 +470,23 @@ msgstr "Aceitando propostas de negócios." #: ../src/net/tmwa/charserverhandler.cpp:105 msgid "Access denied. Most likely, there are too many players on this server." -msgstr "" +msgstr "Acesso negado. Provavelmente há jogadores demais neste servidor." #: ../src/gui/charselectdialog.cpp:113 msgid "Account and Character Management" msgstr "Gestão da Conta e Personagem" #: ../src/net/manaserv/loginhandler.cpp:283 -#, fuzzy msgid "Account banned" -msgstr "A conta expirou" +msgstr "Conta banida" #: ../src/net/manaserv/loginhandler.cpp:98 -#, fuzzy msgid "Account banned." -msgstr "A conta expirou" +msgstr "Conta banida." #: ../src/net/tmwa/loginhandler.cpp:166 -#, fuzzy msgid "Account expired." -msgstr "A conta expirou" +msgstr "A conta expirou." #: ../src/net/manaserv/loginhandler.cpp:129 #: ../src/net/manaserv/loginhandler.cpp:160 @@ -528,39 +504,36 @@ msgstr "Conta: %s" #: ../src/gui/inventorywindow.cpp:106 ../src/gui/popupmenu.cpp:370 msgid "Activate" -msgstr "" +msgstr "Ativar" #: ../src/gui/tradewindow.cpp:76 msgid "Add" msgstr "Adicionar" #: ../src/gui/serverdialog.cpp:192 -#, fuzzy msgid "Add custom Server..." -msgstr "Cursor personalizado" +msgstr "Adicionar servidor personalizado..." #: ../src/gui/popupmenu.cpp:170 -#, fuzzy msgid "Add name to chat" -msgstr "@@name|Adiciona nome ao chat@@" +msgstr "Adicionar nome ao chat" #: ../src/gui/popupmenu.cpp:188 ../src/gui/popupmenu.cpp:391 -#, fuzzy msgid "Add to chat" -msgstr "@@chat|Adicionar ao chat@@" +msgstr "Adicionar ao chat" #: ../src/gui/customserverdialog.cpp:57 msgid "Address:" -msgstr "" +msgstr "Endereço:" #: ../src/net/tmwa/generalhandler.cpp:229 ../src/resources/attributes.cpp:171 msgid "Agility" msgstr "Agilidade" #: ../src/resources/attributes.cpp:177 -#, fuzzy, c-format +#, c-format msgid "Agility %+.1f" -msgstr "Agilidade %+d" +msgstr "Agilidade %+.1f" #: ../src/net/tmwa/generalhandler.cpp:100 #, c-format @@ -593,18 +566,16 @@ msgstr "Permitir sussurros" #: ../src/net/manaserv/loginhandler.cpp:95 #: ../src/net/manaserv/loginhandler.cpp:280 -#, fuzzy msgid "Already logged in." -msgstr "Já está conectado" +msgstr "Já está logado." #: ../src/gui/recorder.cpp:96 msgid "Already recording." msgstr "Já está gravando." #: ../src/gui/setup_video.cpp:246 -#, fuzzy msgid "Ambient FX:" -msgstr "Efeitos Ambientais" +msgstr "Efeitos ambientais:" #: ../src/net/tmwa/inventoryhandler.h:84 msgid "Ammo" @@ -635,20 +606,24 @@ msgid "" "In case OpenGL messes up your game graphics, restart the game with the " "command line option \"--no-opengl\"." msgstr "" +"Aplicar a alteração no OpenGL requer reinício.\n" +"\n" +"Caso o OpenGL atrapalhe os gráficos do seu jogo, reinicie o jogo com a opção " +"de linha de comando \"--no-opengl\"." #: ../src/gui/charselectdialog.cpp:66 msgid "Are you sure you want to delete this character?" -msgstr "Tem a certeza que quer apagar este personagem" +msgstr "Tem certeza de que deseja excluir este personagem?" #: ../src/gui/socialwindow.cpp:154 -#, fuzzy, c-format +#, c-format msgid "Are you sure you want to leave guild %s?" -msgstr "Você tem certeza que deseja sair?" +msgstr "Tem certeza de que deseja sair da guilda %s?" #: ../src/gui/socialwindow.cpp:225 -#, fuzzy, c-format +#, c-format msgid "Are you sure you want to leave party %s?" -msgstr "Você tem certeza que deseja sair?" +msgstr "Tem certeza que deseja sair do grupo %s?" #: ../src/net/tmwa/inventoryhandler.h:66 msgid "Arms" @@ -656,12 +631,12 @@ msgstr "Braços" #: ../src/gui/setup_keyboard.cpp:89 msgid "Assign" -msgstr "Associar" +msgstr "Atribuir" #: ../src/net/manaserv/charhandler.cpp:166 #, c-format msgid "At least one stat is out of the permitted range: (%u - %u)." -msgstr "" +msgstr "Pelo menos um atributo está fora da faixa permitida: (%u - %u)." #: ../src/keyboardconfig.cpp:46 ../src/net/tmwa/generalhandler.cpp:236 msgid "Attack" @@ -670,12 +645,12 @@ msgstr "Ataque" #: ../src/resources/itemdb.cpp:290 #, c-format msgid "Attack %+d" -msgstr "Ataque %+d" +msgstr "Atacar %+d" #: ../src/gui/popupmenu.cpp:83 ../src/gui/popupmenu.cpp:157 -#, fuzzy, c-format +#, c-format msgid "Attack %s" -msgstr "Ataque %+d" +msgstr "Atacar %s" #: ../src/gui/chatwindow.cpp:320 msgid "Attendance written to record log." @@ -686,45 +661,42 @@ msgid "Audio" msgstr "Áudio" #: ../src/net/tmwa/generalhandler.cpp:130 -#, fuzzy msgid "Authentication failed." -msgstr "Autenticação falhou" +msgstr "Autenticação falhou." #: ../src/gui/setup_video.cpp:176 #, c-format msgid "Auto (%dx)" -msgstr "" +msgstr "Auto (%dx)" #: ../src/localplayer.cpp:1023 msgid "Away" -msgstr "" +msgstr "Fora" #: ../src/gui/popupmenu.cpp:96 -#, fuzzy, c-format +#, c-format msgid "Befriend %s" -msgstr "@@friend|Ser amigo de %s@@" +msgstr "Fazer amizade com %s" #: ../src/resources/userpalette.cpp:86 msgid "Being" msgstr "Ser" #: ../src/gui/debugwindow.cpp:141 -#, fuzzy msgid "Being Ids" -msgstr "Ser" +msgstr "IDs de ser" #: ../src/gui/debugwindow.cpp:137 msgid "Being collision radius" -msgstr "" +msgstr "Raio de colisão do ser" #: ../src/gui/debugwindow.cpp:139 -#, fuzzy msgid "Being path" -msgstr "Ser" +msgstr "Caminho do ser" #: ../src/gui/debugwindow.cpp:138 msgid "Being positions" -msgstr "" +msgstr "Posições do ser" #: ../src/net/tmwa/playerhandler.cpp:123 msgid "Bereft of life, you rest in peace." @@ -732,12 +704,11 @@ msgstr "Sem vida, descanse em paz." #: ../src/playerrelations.cpp:346 msgid "Blink name" -msgstr "" +msgstr "Piscar nome" #: ../src/gui/setup_colors.cpp:132 -#, fuzzy msgid "Blue:" -msgstr "Azul: " +msgstr "Azul:" #: ../src/gui/setup_interface.cpp:74 msgid "Bubbles with names" @@ -774,17 +745,16 @@ msgid "" "Cannot create a whisper tab for nick \"%s\"! It either already exists, or is " "you." msgstr "" -"Não é possível criar uma aba de sussurros para o nick \"%s\"! Ou ela já " -"existe ou é você mesmo." +"Não é possível criar uma aba de sussurro para o nick \"%s\"! Ela já existe " +"ou é você." #: ../src/gui/socialwindow.cpp:662 -#, fuzzy msgid "Cannot create party. You are already in a party." -msgstr "/create > Cria um novo grupo" +msgstr "Não é possível criar o grupo. Você já está em um grupo." #: ../src/net/tmwa/playerhandler.cpp:361 msgid "Cannot raise skill!" -msgstr "" +msgstr "Não é possível aumentar a habilidade!" #: ../src/gui/widgets/whispertab.cpp:52 msgid "Cannot send empty chat!" @@ -792,23 +762,21 @@ msgstr "Não é possível enviar chat vazio!" #: ../src/commandhandler.cpp:381 msgid "Cannot send empty whispers!" -msgstr "" +msgstr "Não é possível enviar sussurros vazios!" #: ../src/net/tmwa/specialhandler.cpp:158 msgid "Cannot shout!" msgstr "Impossível gritar!" #: ../src/net/tmwa/charserverhandler.cpp:109 -#, fuzzy msgid "Cannot use this ID." -msgstr "Não é possível usar esta ID" +msgstr "Não é possível usar esta ID." #: ../src/gui/tradewindow.cpp:103 msgid "Change" msgstr "Modificar" #: ../src/gui/charselectdialog.cpp:143 -#, fuzzy msgid "Change Email" msgstr "Alterar e-mail" @@ -817,9 +785,8 @@ msgid "Change Email Address" msgstr "Alterar e-mail" #: ../src/gui/worldselectdialog.cpp:73 -#, fuzzy msgid "Change Login" -msgstr "Modificar" +msgstr "Mudar login" #: ../src/gui/changepassworddialog.cpp:47 #: ../src/gui/changepassworddialog.cpp:56 ../src/gui/charselectdialog.cpp:121 @@ -827,23 +794,20 @@ msgid "Change Password" msgstr "Alterar Senha" #: ../src/gui/logindialog.cpp:54 -#, fuzzy msgid "Change Server" -msgstr "Servidor" +msgstr "Mudar Servidor" #: ../src/gui/setup_video.cpp:504 msgid "Changes will take effect on map change." msgstr "As mudanças terão efeito na mudança do mapa." #: ../src/client.cpp:776 -#, fuzzy msgid "Changing game servers" -msgstr "Servidor" +msgstr "Mudando de servidores de jogo" #: ../src/gui/setup_video.cpp:385 -#, fuzzy msgid "Changing to OpenGL" -msgstr "Mudando OpenGL" +msgstr "Mudando para OpenGL" #: ../src/gui/widgets/channeltab.cpp:83 msgid "Channel operators can kick and op other users from the channel." @@ -862,28 +826,25 @@ msgid "Character deleted." msgstr "Personagem apagado." #: ../src/gui/statuswindow.cpp:214 ../src/gui/statuswindow.cpp:251 -#, fuzzy, c-format +#, c-format msgid "Character points: %d" -msgstr "Estatisticas da personagem OK" +msgstr "Pontos de personagem: %d" #: ../src/gui/charcreatedialog.cpp:269 msgid "Character stats OK" msgstr "Estatisticas da personagem OK" #: ../src/net/manaserv/charhandler.cpp:148 -#, fuzzy msgid "Character's name already exists." -msgstr "Nome de utilizador já existe" +msgstr "O nome do personagem já existe." #: ../src/net/manaserv/charhandler.cpp:160 -#, fuzzy msgid "Character's stats are too high." -msgstr "Estatisticas da personagem OK" +msgstr "Os atributos do personagem estão muito altos." #: ../src/net/manaserv/charhandler.cpp:163 -#, fuzzy msgid "Character's stats are too low." -msgstr "Estatisticas da personagem OK" +msgstr "Os atributos do personagem estão muito baixos." #: ../src/gui/chatwindow.cpp:87 msgid "Chat" @@ -898,49 +859,44 @@ msgid "Chat creating failed!" msgstr "Falha ao criar Chat!" #: ../src/gui/charselectdialog.cpp:381 -#, fuzzy msgid "Choose" -msgstr "Fechar" +msgstr "Escolher" #: ../src/gui/worldselectdialog.cpp:74 -#, fuzzy msgid "Choose World" -msgstr "Selecione seu servidor" +msgstr "Escolher Mundo" #: ../src/gui/serverdialog.cpp:172 -#, fuzzy msgid "Choose Your Server" -msgstr "Selecione seu servidor" +msgstr "Escolha seu Servidor" #: ../src/gui/socialwindow.cpp:584 -#, fuzzy msgid "Choose your guild's name." -msgstr "Selecione seu servidor" +msgstr "Escolha o nome da sua guilda." #: ../src/gui/socialwindow.cpp:668 -#, fuzzy msgid "Choose your party's name." -msgstr "Selecione seu servidor" +msgstr "Escolha o nome do seu grupo." #: ../src/gui/npcdialog.cpp:116 msgid "Clear log" -msgstr "" +msgstr "Limpar log" #: ../src/net/manaserv/loginhandler.cpp:244 msgid "" "Client registration is not allowed. Please contact server administration." msgstr "" +"O registro de cliente não é permitido. Por favor, entre em contato com a " +"administração do servidor." #: ../src/net/tmwa/loginhandler.cpp:176 -#, fuzzy msgid "Client too old." -msgstr "Versão do cliente é muito antiga" +msgstr "O cliente é muito antigo." #: ../src/net/manaserv/loginhandler.cpp:274 #: ../src/net/manaserv/loginhandler.cpp:311 -#, fuzzy msgid "Client version is too old." -msgstr "Versão do cliente é muito antiga" +msgstr "Versão do cliente é muito antiga." #: ../src/gui/helpwindow.cpp:52 ../src/gui/npcdialog.cpp:51 msgid "Close" @@ -948,21 +904,19 @@ msgstr "Fechar" #: ../src/gui/debugwindow.cpp:136 msgid "Collision tiles" -msgstr "" +msgstr "Blocos de colisão" #: ../src/gui/setup_colors.cpp:48 msgid "Colors" msgstr "Cores" #: ../src/commandhandler.cpp:254 -#, fuzzy msgid "Command: /away" -msgstr "Comando: /who" +msgstr "Comando: /away" #: ../src/commandhandler.cpp:251 -#, fuzzy msgid "Command: /away <afk reason>" -msgstr "Comando: /w <nick> <mensagem>" +msgstr "Comando: /away <motivo>" #: ../src/commandhandler.cpp:208 msgid "Command: /clear" @@ -973,9 +927,8 @@ msgid "Command: /close" msgstr "Comando: /close" #: ../src/commandhandler.cpp:259 -#, fuzzy msgid "Command: /createparty <name>" -msgstr "Comando: /create <nome-do-grupo>" +msgstr "Comando: /createparty <nome>" #: ../src/net/tmwa/gui/partytab.cpp:93 msgid "Command: /exp" @@ -994,14 +947,12 @@ msgid "Command: /help <command>" msgstr "Comando: /help <command>" #: ../src/gui/widgets/whispertab.cpp:88 -#, fuzzy msgid "Command: /ignore" -msgstr "Comando: /item" +msgstr "Comando: /ignore" #: ../src/commandhandler.cpp:213 -#, fuzzy msgid "Command: /ignore <player>" -msgstr "Comando> /item <opção>" +msgstr "Comando: /ignore <jogador>" #: ../src/net/tmwa/gui/guildtab.cpp:65 ../src/net/tmwa/gui/partytab.cpp:66 msgid "Command: /invite <nick>" @@ -1084,9 +1035,8 @@ msgid "Command: /topic <message>" msgstr "Comando: /topic <mensagem>" #: ../src/commandhandler.cpp:297 ../src/gui/widgets/whispertab.cpp:94 -#, fuzzy msgid "Command: /unignore <player>" -msgstr "Comando> /item <opção>" +msgstr "Comando: /unignore <jogador>" #: ../src/gui/widgets/channeltab.cpp:62 msgid "Command: /users" @@ -1113,14 +1063,13 @@ msgid "Completed" msgstr "Concluído" #: ../src/playerrelations.cpp:316 -#, fuzzy msgid "Completely ignore" -msgstr "@@ignore|Ignorar completamente %s@@" +msgstr "Ignorar completamente" #: ../src/gui/popupmenu.cpp:113 -#, fuzzy, c-format +#, c-format msgid "Completely ignore %s" -msgstr "@@ignore|Ignorar completamente %s@@" +msgstr "Ignorar %s completamente" #: ../src/gui/charselectdialog.cpp:65 msgid "Confirm Character Delete" @@ -1135,49 +1084,46 @@ msgid "Confirmed. Waiting..." msgstr "Confirmado. Aguardando..." #: ../src/keyboardconfig.cpp:185 -#, fuzzy, c-format +#, c-format msgid "" "Conflict \"%s\" and \"%s\" keys. Resolve them, or gameplay may result in " "strange behaviour." -msgstr "Corrija-os, ou o jogo irá se comportar de forma estranha." +msgstr "" +"Conflito entre as teclas \"%s\" e \"%s\". Resolva-as, ou a jogabilidade pode " +"apresentar comportamentos estranhos." #: ../src/gui/serverdialog.cpp:191 -#, fuzzy msgid "Connect" -msgstr "Conectando..." +msgstr "Conectar" #: ../src/client.cpp:605 -#, fuzzy msgid "Connecting to server" -msgstr "Conectando ao servidor de mapas..." +msgstr "Conectando ao servidor" #: ../src/client.cpp:766 -#, fuzzy msgid "Connecting to the game server" -msgstr "Conectando ao servidor de mapas..." +msgstr "Conectando ao servidor do jogo" #: ../src/gui/updaterwindow.cpp:138 msgid "Connecting..." msgstr "Conectando…" #: ../src/net/tmwa/network.cpp:540 -#, fuzzy msgid "Connection to server terminated. " -msgstr "Conectando ao servidor de mapas..." +msgstr "Conexão com o servidor encerrada. " #: ../src/keyboardconfig.cpp:85 msgid "Copy Outfit" -msgstr "" +msgstr "Copiar traje" #: ../src/gui/statuswindow.cpp:259 -#, fuzzy, c-format +#, c-format msgid "Correction points: %d" -msgstr "Pontos de habilidade: %d" +msgstr "Pontos de correção: %d" #: ../src/game.cpp:941 -#, fuzzy msgid "Could Not Load Map" -msgstr "Impossível carregar mapa" +msgstr "Não foi possível carregar o mapa" #: ../src/net/tmwa/partyhandler.cpp:82 msgid "Could not create party." @@ -1192,9 +1138,8 @@ msgid "Could not steal anything..." msgstr "Não foi possível roubar nada..." #: ../src/game.cpp:290 -#, fuzzy msgid "Could not take screenshot!" -msgstr "Não foi possível criar o grupo." +msgstr "Não foi possível tirar a captura de tela!" #: ../src/gui/charcreatedialog.cpp:85 ../src/gui/charselectdialog.cpp:393 #: ../src/gui/socialwindow.cpp:365 @@ -1210,27 +1155,26 @@ msgid "Create Guild" msgstr "Criar Guilda" #: ../src/gui/socialwindow.cpp:311 ../src/gui/socialwindow.cpp:661 -#, fuzzy msgid "Create Party" -msgstr "Criar Personagem" +msgstr "Criar grupo" #: ../src/gui/socialwindow.cpp:545 -#, fuzzy, c-format +#, c-format msgid "Creating guild called %s." -msgstr "Erro ao criar guilda." +msgstr "Criando guilda chamada %s." #: ../src/gui/socialwindow.cpp:537 msgid "Creating guild failed, please choose a shorter name." -msgstr "" +msgstr "Falha ao criar a guilda, por favor, escolha um nome mais curto." #: ../src/gui/socialwindow.cpp:569 #, c-format msgid "Creating party called %s." -msgstr "" +msgstr "Criando grupo chamado %s." #: ../src/gui/socialwindow.cpp:561 msgid "Creating party failed, please choose a shorter name." -msgstr "" +msgstr "Falha ao criar o grupo, por favor, escolha um nome mais curto." #: ../src/resources/userpalette.cpp:100 msgid "Critical Hit" @@ -1239,17 +1183,15 @@ msgstr "Golpe crítico" #: ../src/gui/debugwindow.cpp:97 #, c-format msgid "Cursor: (%d, %d)" -msgstr "" +msgstr "Cursor: (%d, %d)" #: ../src/gui/setup_video.cpp:102 -#, fuzzy msgid "Custom" -msgstr "Cursor personalizado" +msgstr "Personalizado" #: ../src/gui/customserverdialog.cpp:50 -#, fuzzy msgid "Custom Server" -msgstr "Cursor personalizado" +msgstr "Servidor personalizado" #: ../src/gui/setup_video.cpp:229 msgid "Custom cursor" @@ -1257,11 +1199,11 @@ msgstr "Cursor personalizado" #: ../src/gui/setup_video.cpp:393 msgid "Deactivating OpenGL" -msgstr "" +msgstr "Desativando OpenGL" #: ../src/gui/debugwindow.cpp:232 msgid "Debug" -msgstr "" +msgstr "Depuração" #: ../src/keyboardconfig.cpp:80 msgid "Debug Window" @@ -1272,9 +1214,8 @@ msgid "Default" msgstr "Padrão" #: ../src/net/tmwa/generalhandler.cpp:237 -#, fuzzy msgid "Defense" -msgstr "Defesa:" +msgstr "Defesa" #: ../src/resources/itemdb.cpp:291 #, c-format @@ -1282,9 +1223,8 @@ msgid "Defense %+d" msgstr "Defesa %+d" #: ../src/gui/setup_colors.cpp:87 -#, fuzzy msgid "Delay:" -msgstr "Atraso: " +msgstr "Atraso:" #: ../src/gui/charselectdialog.cpp:340 ../src/gui/serverdialog.cpp:194 #: ../src/gui/setup_players.cpp:221 @@ -1292,18 +1232,17 @@ msgid "Delete" msgstr "Eliminar" #: ../src/gui/customserverdialog.cpp:62 -#, fuzzy msgid "Description:" -msgstr "Descrição: %s" +msgstr "Descrição:" #: ../src/net/tmwa/generalhandler.cpp:233 ../src/resources/attributes.cpp:183 msgid "Dexterity" msgstr "Destreza" #: ../src/resources/attributes.cpp:189 -#, fuzzy, c-format +#, c-format msgid "Dexterity %+.1f" -msgstr "Destreza %+d" +msgstr "Destreza %+.1f" #: ../src/net/tmwa/generalhandler.cpp:103 #, c-format @@ -1316,12 +1255,12 @@ msgstr "Destreza:" #: ../src/gui/setup_video.cpp:241 msgid "Disable transparency (Low CPU mode)" -msgstr "" +msgstr "Desativar transparência (Modo de baixa CPU)" #: ../src/gui/popupmenu.cpp:101 -#, fuzzy, c-format +#, c-format msgid "Disregard %s" -msgstr "Desconsiderado" +msgstr "Desconsiderar %s" #: ../src/gui/setup_players.cpp:63 msgid "Disregarded" @@ -1334,12 +1273,12 @@ msgstr "Você quer uma identificação de suas posses?" #: ../src/gui/setup_audio.cpp:43 msgid "Download music" -msgstr "" +msgstr "Baixar música" #: ../src/gui/serverdialog.cpp:389 #, c-format msgid "Downloading server list...%2.2f%%" -msgstr "" +msgstr "Baixando lista de servidores...%2.2f%%" #: ../src/gui/inventorywindow.cpp:387 ../src/gui/popupmenu.cpp:377 msgid "Drop" @@ -1347,29 +1286,24 @@ msgstr "Largar" #: ../src/gui/inventorywindow.cpp:107 ../src/gui/inventorywindow.cpp:385 #: ../src/gui/popupmenu.cpp:375 -#, fuzzy msgid "Drop..." -msgstr "Largar" +msgstr "Descartar..." #: ../src/net/tmwa/generalhandler.cpp:146 -#, fuzzy msgid "Duplicated login." -msgstr "Login duplicado" +msgstr "Login duplicado." #: ../src/client.cpp:864 -#, fuzzy msgid "Email Change" -msgstr "Modificar" +msgstr "Mudar email" #: ../src/net/manaserv/loginhandler.cpp:320 -#, fuzzy msgid "Email address already exists." -msgstr "Endereço de email já existe" +msgstr "Endereço de email já existe." #: ../src/client.cpp:865 -#, fuzzy msgid "Email changed successfully!" -msgstr "Membro foi promovido com sucesso." +msgstr "Email alterado com sucesso!" #: ../src/gui/register.cpp:100 msgid "Email:" @@ -1395,12 +1329,11 @@ msgstr "Falha no Emote!" #: ../src/net/tmwa/network.cpp:289 msgid "Empty address given to Network::connect()!" -msgstr "" +msgstr "Endereço vazio fornecido para Network::connect()!" #: ../src/gui/setup_players.cpp:227 -#, fuzzy msgid "Enable Chat log" -msgstr "Impossibilitado de vender." +msgstr "Ativar log de chat" #: ../src/gui/setup_joystick.cpp:38 msgid "Enable joystick" @@ -1412,15 +1345,15 @@ msgstr "Habilitar/Desabilitar Negociações" #: ../src/net/manaserv/chathandler.cpp:229 msgid "End of channel list." -msgstr "" +msgstr "Fim da lista de canais." #: ../src/gui/changepassworddialog.cpp:110 msgid "Enter the old password first." -msgstr "" +msgstr "Digite a senha antiga primeiro." #: ../src/client.cpp:659 msgid "Entering game world" -msgstr "" +msgstr "Entrando no mundo do jogo" #: ../src/gui/inventorywindow.cpp:92 ../src/gui/inventorywindow.cpp:105 #: ../src/gui/inventorywindow.cpp:374 ../src/gui/popupmenu.cpp:367 @@ -1456,27 +1389,30 @@ msgid "Error creating guild." msgstr "Erro ao criar guilda." #: ../src/client.cpp:1203 -#, fuzzy, c-format +#, c-format msgid "" "Error creating updates directory!\n" "(%s)" -msgstr "Erro ao criar pasta de actualizações!" +msgstr "" +"Erro ao criar o pasta de atualizações!\n" +"(%s)" #: ../src/client.cpp:1211 -#, fuzzy, c-format +#, c-format msgid "" "Error creating updates directory!\n" "(%s/%s)" -msgstr "Erro ao criar pasta de actualizações!" +msgstr "" +"Erro ao criar o pasta de atualizações!\n" +"(%s/%s)" #: ../src/net/manaserv/chathandler.cpp:211 -#, fuzzy msgid "Error joining channel." -msgstr "Comando: /join <canal>" +msgstr "Erro ao entrar no canal." #: ../src/gui/serverdialog.cpp:403 msgid "Error retreiving server list!" -msgstr "" +msgstr "Erro ao recuperar a lista de servidores!" #: ../src/game.cpp:942 #, c-format @@ -1504,12 +1440,10 @@ msgid "Experience sharing not possible." msgstr "Não é possível partilhar experiência." #: ../src/net/tmwa/gui/partytab.cpp:169 -#, fuzzy msgid "Experience sharing unknown." -msgstr "Partilha de experiência habilitado." +msgstr "Compartilhamento de experiência desconhecido." #: ../src/gui/setup_video.cpp:231 -#, fuzzy msgid "FPS limit:" msgstr "Limite de FPS:" @@ -1526,21 +1460,17 @@ msgid "Failed adding item. Trade partner is over weighted." msgstr "Erro ao adicionar item. Parceiro de negócios carregando muito peso." #: ../src/net/tmwa/tradehandler.cpp:214 -#, fuzzy msgid "Failed adding item. You can't trade this item." -msgstr "" -"Falha ao adicionar item. Você não pode duplicar um tipo de item na janela." +msgstr "Falha ao adicionar item. Você não pode trocar este item." #: ../src/gui/tradewindow.cpp:262 -#, fuzzy msgid "Failed adding item. You cannot overlap one kind of item on the window." msgstr "" -"Falha ao adicionar item. Você não pode duplicar um tipo de item na janela." +"Falha ao adicionar item. Você não pode sobrepor um tipo de item na janela." #: ../src/gui/setup_video.cpp:374 -#, fuzzy msgid "Failed to change video mode." -msgstr "Problemas ao usar item." +msgstr "Falha ao mudar o modo de vídeo." #: ../src/net/tmwa/charserverhandler.cpp:136 msgid "Failed to create character. Most likely the name is already taken." @@ -1568,11 +1498,11 @@ msgstr "Problemas ao usar item." #: ../src/client.cpp:885 msgid "Farewell, come back any time..." -msgstr "" +msgstr "Adeus, volte sempre..." #: ../src/net/tmwa/inventoryhandler.h:72 msgid "Feet" -msgstr "" +msgstr "Pés" #: ../src/gui/charcreatedialog.cpp:88 ../src/gui/register.cpp:91 msgid "Female" @@ -1583,9 +1513,8 @@ msgid "Finishing recording." msgstr "Finalizando gravação." #: ../src/gui/setup_interface.cpp:113 -#, fuzzy msgid "Font size:" -msgstr "Tamanho da fonte" +msgstr "Tamanho da fonte:" #: ../src/commandhandler.cpp:192 msgid "For more information, type /help <command>." @@ -1596,9 +1525,8 @@ msgid "Friend" msgstr "Amigo" #: ../src/gui/setup_video.cpp:221 -#, fuzzy msgid "Fullscreen" -msgstr "Ecrã completo" +msgstr "Tela cheia" #: ../src/resources/userpalette.cpp:89 msgid "GM Names" @@ -1606,17 +1534,15 @@ msgstr "Nomes dos GMs" #: ../src/gui/debugwindow.cpp:142 msgid "GUI debug" -msgstr "" +msgstr "Depuração da interface gráfica" #: ../src/gui/setup_interface.cpp:112 -#, fuzzy msgid "GUI opacity" -msgstr "Opacidade do Interface" +msgstr "Opacidade da interface gráfica" #: ../src/net/tmwa/gamehandler.cpp:89 -#, fuzzy msgid "Game" -msgstr "Nome" +msgstr "Jogo" #: ../src/net/manaserv/beinghandler.cpp:283 #: ../src/net/tmwa/playerhandler.cpp:99 @@ -1641,46 +1567,41 @@ msgid "Got disconnected from server!" msgstr "Você foi desconectado do servidor!" #: ../src/gui/setup_colors.cpp:117 -#, fuzzy msgid "Green:" -msgstr "Verde: " +msgstr "Verde:" #: ../src/gui/debugwindow.cpp:135 msgid "Grid" -msgstr "" +msgstr "Grade" #: ../src/net/tmwa/gui/guildtab.cpp:41 msgid "Guild" msgstr "Guilda" #: ../src/gui/socialwindow.cpp:129 -#, fuzzy, c-format +#, c-format msgid "Guild %s quit requested." -msgstr "Guilda criada." +msgstr "Solicitada a saída da guilda %s." #: ../src/resources/userpalette.cpp:93 -#, fuzzy msgid "Guild Members" -msgstr "Guilda" +msgstr "Membros da guilda" #: ../src/gui/socialwindow.cpp:583 -#, fuzzy msgid "Guild Name" -msgstr "Guilda" +msgstr "Nome da guilda" #: ../src/net/manaserv/guildhandler.cpp:80 msgid "Guild created." msgstr "Guilda criada." #: ../src/net/tmwa/guildhandler.cpp:63 -#, fuzzy msgid "Guild creation isn't supported." -msgstr "Guilda criada." +msgstr "A criação de guilda não é suportada." #: ../src/net/tmwa/gui/guildtab.cpp:81 -#, fuzzy msgid "Guild name is missing." -msgstr "Falta o nome do grupo." +msgstr "Falta o nome da guilda." #: ../src/resources/itemdb.cpp:292 #, c-format @@ -1692,26 +1613,24 @@ msgid "HP:" msgstr "HP:" #: ../src/gui/charcreatedialog.cpp:78 -#, fuzzy msgid "Hair color:" msgstr "Cor de Cabelo:" #: ../src/gui/charcreatedialog.cpp:84 -#, fuzzy msgid "Hair style:" msgstr "Estilo do Cabelo:" #: ../src/net/tmwa/inventoryhandler.h:80 msgid "Hand 1/2" -msgstr "" +msgstr "Mão 1/2" #: ../src/net/tmwa/inventoryhandler.h:82 msgid "Hand 2/2" -msgstr "" +msgstr "Mão 2/2" #: ../src/net/tmwa/inventoryhandler.h:68 msgid "Head" -msgstr "" +msgstr "Cabeça" #: ../src/gui/helpwindow.cpp:38 msgid "Help" @@ -1753,9 +1672,9 @@ msgid "If you're the last person in the channel, it will be deleted." msgstr "Se você for a última pessoa no canal, ele será apagado." #: ../src/gui/popupmenu.cpp:104 -#, fuzzy, c-format +#, c-format msgid "Ignore %s" -msgstr "Ignorado" +msgstr "Ignorar %s" #: ../src/keyboardconfig.cpp:105 msgid "Ignore input 1" @@ -1799,9 +1718,9 @@ msgid "Intelligence" msgstr "Inteligência" #: ../src/resources/attributes.cpp:213 -#, fuzzy, c-format +#, c-format msgid "Intelligence %+.1f" -msgstr "Inteligência %+d" +msgstr "Inteligência %+.1f" #: ../src/net/tmwa/generalhandler.cpp:102 #, c-format @@ -1814,41 +1733,41 @@ msgstr "Inteligência:" #: ../src/gui/setup_interface.cpp:103 msgid "Interface" -msgstr "" +msgstr "Interface" #: ../src/net/manaserv/charhandler.cpp:268 -#, fuzzy msgid "Invalid character slot selected." -msgstr "Personagem apagado." +msgstr "Slot de personagem inválido selecionado." #: ../src/net/manaserv/charhandler.cpp:157 msgid "Invalid gender." -msgstr "" +msgstr "Gênero inválido." #: ../src/net/manaserv/charhandler.cpp:154 msgid "Invalid hair color." -msgstr "" +msgstr "Cor de cabelo inválida." #: ../src/net/manaserv/charhandler.cpp:151 msgid "Invalid hairstyle." -msgstr "" +msgstr "Penteado inválido." #: ../src/net/manaserv/charhandler.cpp:145 msgid "Invalid name." -msgstr "" +msgstr "Nome inválido." #: ../src/main.cpp:173 msgid "Invalid server type, expected one of: tmwathena, manaserv" msgstr "" +"Tipo de servidor inválido, esperava-se um dos seguintes: tmwathena, manaserv" #: ../src/net/manaserv/charhandler.cpp:172 msgid "Invalid slot number." -msgstr "" +msgstr "Número de slot inválido." #: ../src/client.cpp:1171 -#, fuzzy, c-format +#, c-format msgid "Invalid update host: %s" -msgstr "Host de atualização inválido: " +msgstr "Host de atualização inválido: %s" #: ../src/gui/inventorywindow.cpp:60 ../src/gui/windowmenu.cpp:55 msgid "Inventory" @@ -1859,57 +1778,53 @@ msgid "Inventory Window" msgstr "Janela de inventário" #: ../src/localplayer.cpp:867 -#, fuzzy msgid "Inventory is full." -msgstr "Servidor cheio" +msgstr "Inventário cheio." #: ../src/gui/socialwindow.cpp:366 -#, fuzzy msgid "Invite" -msgstr "Convidar Usuário" +msgstr "Convidar" #: ../src/gui/popupmenu.cpp:126 -#, fuzzy, c-format +#, c-format msgid "Invite %s to join your guild" -msgstr "@@guild|Convidar %s para sua Guilda@@" +msgstr "Convidar %s para sua guilda" #: ../src/gui/popupmenu.cpp:132 -#, fuzzy, c-format +#, c-format msgid "Invite %s to join your party" -msgstr "@@party|Convidar %s para entrar no seu grupo@@" +msgstr "Convidar %s para se juntar ao seu grupo" #: ../src/net/manaserv/guildhandler.cpp:108 -#, fuzzy msgid "Invite failed." -msgstr "Falha ao sentar!" +msgstr "Convite falhou." #: ../src/net/manaserv/guildhandler.cpp:96 msgid "Invite sent." msgstr "Convite enviado." #: ../src/net/manaserv/guildhandler.cpp:104 -#, fuzzy msgid "Invited player can't join another guild." -msgstr "@@guild|Convidar %s para sua Guilda@@" +msgstr "O jogador convidado não pode entrar em outra guilda." #: ../src/net/manaserv/guildhandler.cpp:100 msgid "Invited player is already in that guild." -msgstr "" +msgstr "O jogador convidado já está nessa guilda." #: ../src/gui/socialwindow.cpp:116 #, c-format msgid "Invited user %s to guild %s." -msgstr "" +msgstr "Convidou o usuário %s para a guilda %s." #: ../src/gui/socialwindow.cpp:189 ../src/net/tmwa/partyhandler.cpp:318 -#, fuzzy, c-format +#, c-format msgid "Invited user %s to party." -msgstr "/party > convidar um jogadora para a equipa" +msgstr "Convidou o usuário %s para o grupo." #: ../src/net/tmwa/partyhandler.cpp:323 #, c-format msgid "Inviting failed, because you can't see a player called %s." -msgstr "" +msgstr "Convite falhou, porque você não pode ver um jogador chamado %s." #: ../src/keyboardconfig.cpp:59 ../src/keyboardconfig.cpp:60 #: ../src/keyboardconfig.cpp:61 ../src/keyboardconfig.cpp:62 @@ -1927,15 +1842,15 @@ msgstr "Janela de atalhos para itens" #: ../src/localplayer.cpp:870 msgid "Item belongs to someone else." -msgstr "" +msgstr "O item pertence a outra pessoa." #: ../src/localplayer.cpp:866 msgid "Item is too far away" -msgstr "" +msgstr "O item está muito longe" #: ../src/localplayer.cpp:865 msgid "Item is too heavy." -msgstr "" +msgstr "O item é muito pesado." #: ../src/net/tmwa/gui/partytab.cpp:128 ../src/net/tmwa/partyhandler.cpp:202 msgid "Item sharing disabled." @@ -1950,9 +1865,8 @@ msgid "Item sharing not possible." msgstr "Não é possível partilhar itens." #: ../src/net/tmwa/gui/partytab.cpp:134 -#, fuzzy msgid "Item sharing unknown." -msgstr "Partilha de itens habilitado." +msgstr "Compartilhamento de itens desconhecido." #: ../src/gui/statuswindow.cpp:162 msgid "Job:" @@ -1966,11 +1880,11 @@ msgstr "Trabalho: %d" #: ../src/net/manaserv/partyhandler.cpp:98 msgid "" "Joining party failed, because the invitation has timed out on the server." -msgstr "" +msgstr "Falha ao entrar no grupo, porque o convite expirou no servidor." #: ../src/net/manaserv/partyhandler.cpp:102 msgid "Joining party failed, because the inviter has left the game." -msgstr "" +msgstr "Falha ao entrar no grupo, pois o jogador que convidou saiu do jogo." #: ../src/gui/setup_joystick.cpp:40 msgid "Joystick" @@ -1989,14 +1903,12 @@ msgid "Kick failed!" msgstr "Erro na expulsão!" #: ../src/gui/popupmenu.cpp:162 -#, fuzzy msgid "Kick monster" -msgstr "@@admin-kick|Expulsar monstro@@" +msgstr "Expulsar monstro" #: ../src/gui/popupmenu.cpp:140 -#, fuzzy msgid "Kick player" -msgstr "Erro na expulsão!" +msgstr "Expulsar jogador" #: ../src/net/tmwa/adminhandler.cpp:65 msgid "Kick succeeded!" @@ -2007,22 +1919,20 @@ msgid "Large" msgstr "Grande" #: ../src/gui/socialwindow.cpp:367 -#, fuzzy msgid "Leave" -msgstr "Grande" +msgstr "Sair" #: ../src/gui/socialwindow.cpp:153 -#, fuzzy msgid "Leave Guild?" -msgstr "Criar Guilda" +msgstr "Sair da guilda?" #: ../src/gui/socialwindow.cpp:224 msgid "Leave Party?" -msgstr "" +msgstr "Sair do grupo?" #: ../src/net/tmwa/inventoryhandler.h:70 msgid "Legs" -msgstr "" +msgstr "Pernas" #: ../src/gui/statuswindow.cpp:116 ../src/gui/statuswindow.cpp:218 #: ../src/gui/statuswindow.cpp:266 @@ -2031,32 +1941,28 @@ msgid "Level: %d" msgstr "Nível: %d" #: ../src/net/manaserv/chathandler.cpp:217 -#, fuzzy msgid "Listing channels." -msgstr "Solicitando entrada no canal %s." +msgstr "Listando canais." #: ../src/resources/userpalette.cpp:104 -#, fuzzy msgid "Local Player Critical Hit" -msgstr "Golpe crítico" +msgstr "Acerto Crítico do jogador local" #: ../src/resources/userpalette.cpp:102 -#, fuzzy msgid "Local Player Hits Monster" -msgstr "Jogador acerta monstro" +msgstr "Jogador Local Ataca Monstro" #: ../src/resources/userpalette.cpp:106 msgid "Local Player Miss" -msgstr "" +msgstr "Jogador Local Errou" #: ../src/gui/setup_interface.cpp:91 msgid "Log NPC dialogue" -msgstr "" +msgstr "Logar diálogos NPC" #: ../src/client.cpp:631 -#, fuzzy msgid "Logging in" -msgstr "Autenticar" +msgstr "Fazendo login" #: ../src/gui/logindialog.cpp:43 ../src/gui/logindialog.cpp:55 msgid "Login" @@ -2064,7 +1970,7 @@ msgstr "Autenticar" #: ../src/net/manaserv/loginhandler.cpp:286 msgid "Login attempt too soon after previous attempt." -msgstr "" +msgstr "Tentativa de login muito breve após a tentativa anterior." #: ../src/net/manaserv/beinghandler.cpp:292 #: ../src/net/tmwa/playerhandler.cpp:113 @@ -2085,24 +1991,22 @@ msgid "Luck:" msgstr "Sorte:" #: ../src/gui/skilldialog.cpp:468 -#, fuzzy, c-format +#, c-format msgid "Lvl: %d" -msgstr "Nível: %d" +msgstr "Lvl: %d" #: ../src/gui/skilldialog.cpp:457 -#, fuzzy, c-format +#, c-format msgid "Lvl: %d (%+d)" -msgstr "Nível: %d" +msgstr "Lvl: %d (%+d)" #: ../src/net/tmwa/generalhandler.cpp:238 -#, fuzzy msgid "M.Attack" -msgstr "M. Ataque:" +msgstr "Ataque M." #: ../src/net/tmwa/generalhandler.cpp:239 -#, fuzzy msgid "M.Defense" -msgstr "M. Defesa:" +msgstr "Defesa M." #: ../src/resources/itemdb.cpp:293 #, c-format @@ -2122,9 +2026,9 @@ msgid "Map" msgstr "Mapa" #: ../src/gui/debugwindow.cpp:104 -#, fuzzy, c-format +#, c-format msgid "Map: %s" -msgstr "Nome: %s" +msgstr "Mapa: %s" #: ../src/gui/buydialog.cpp:79 ../src/gui/selldialog.cpp:79 #: ../src/gui/statuswindow.cpp:394 ../src/gui/statuswindow.cpp:466 @@ -2138,12 +2042,11 @@ msgstr "Médio" #: ../src/gui/socialwindow.cpp:143 msgid "Member Invite to Guild" -msgstr "" +msgstr "Convite para membro da guilda" #: ../src/gui/socialwindow.cpp:214 -#, fuzzy msgid "Member Invite to Party" -msgstr "/party > convidar um jogadora para a equipa" +msgstr "Membro Convidado para o Grupo" #: ../src/net/manaserv/guildhandler.cpp:215 msgid "Member was promoted successfully." @@ -2166,9 +2069,9 @@ msgid "Minimap Window" msgstr "Janela de Mini-mapa" #: ../src/gui/debugwindow.cpp:102 -#, fuzzy, c-format +#, c-format msgid "Minimap: %s" -msgstr "MiniMapa" +msgstr "Minimapa: %s" #: ../src/resources/userpalette.cpp:107 msgid "Misses" @@ -2176,7 +2079,7 @@ msgstr "Falhas" #: ../src/gui/serverdialog.cpp:193 msgid "Modify..." -msgstr "" +msgstr "Modificar..." #: ../src/gui/statuswindow.cpp:117 ../src/gui/statuswindow.cpp:211 #: ../src/gui/statuswindow.cpp:243 @@ -2185,7 +2088,6 @@ msgid "Money: %s" msgstr "Dinheiro: %s" #: ../src/resources/userpalette.cpp:99 -#, fuzzy msgid "Monster Hits Player" msgstr "Monstro acerta jogador" @@ -2195,7 +2097,7 @@ msgstr "Monstros" #: ../src/gui/debugwindow.cpp:140 msgid "Mouse path" -msgstr "" +msgstr "Caminho do mouse" #: ../src/keyboardconfig.cpp:43 msgid "Move Down" @@ -2218,9 +2120,9 @@ msgid "Music volume" msgstr "Volume da Música" #: ../src/gui/debugwindow.cpp:101 -#, fuzzy, c-format +#, c-format msgid "Music: %s" -msgstr "Tópico: %s" +msgstr "Música: %s" #: ../src/gui/npcdialog.cpp:72 ../src/gui/npcpostdialog.cpp:41 msgid "NPC" @@ -2245,13 +2147,12 @@ msgid "Name: %s" msgstr "Nome: %s" #: ../src/net/tmwa/inventoryhandler.h:78 -#, fuzzy msgid "Necklace" -msgstr "Colares" +msgstr "Colar" #: ../src/gui/ministatuswindow.cpp:244 msgid "Need" -msgstr "" +msgstr "Precisa" #: ../src/gui/widgets/channeltab.cpp:121 msgid "Need a user to kick!" @@ -2270,19 +2171,16 @@ msgid "Neutral" msgstr "Neutro" #: ../src/net/manaserv/loginhandler.cpp:154 -#, fuzzy msgid "New email address incorrect." -msgstr "Novo endereço de email incorrecto" +msgstr "Novo endereço de email incorreto." #: ../src/net/manaserv/loginhandler.cpp:123 -#, fuzzy msgid "New password incorrect." -msgstr "Nova senha incorreta" +msgstr "Nova senha incorreta." #: ../src/net/tmwa/loginhandler.cpp:95 -#, fuzzy msgid "New password too short." -msgstr "Nova senha é muito curta" +msgstr "Nova senha é muito curta." #: ../src/gui/npcdialog.cpp:50 msgid "Next" @@ -2298,25 +2196,23 @@ msgstr "Não" #: ../src/commandhandler.cpp:388 msgid "No <nick> was given." -msgstr "" +msgstr "Nenhum <nick> foi fornecido." #: ../src/net/manaserv/charhandler.cpp:142 msgid "No empty slot." -msgstr "" +msgstr "Sem slot vazio." #: ../src/net/manaserv/charhandler.cpp:265 msgid "No gameservers are available." msgstr "Não há gameservers disponíveis." #: ../src/gui/itempopup.cpp:127 -#, fuzzy msgid "No item" -msgstr "Item desconhecido" +msgstr "Sem item" #: ../src/net/tmwa/generalhandler.cpp:133 -#, fuzzy msgid "No servers available." -msgstr "Não há servidores disponíveis" +msgstr "Não há servidores disponíveis." #: ../src/gui/setup_interface.cpp:71 msgid "No text" @@ -2333,13 +2229,12 @@ msgstr "" #: ../src/gui/setup_video.cpp:253 ../src/gui/setup_video.cpp:450 #: ../src/gui/setup_video.cpp:525 -#, fuzzy msgid "None" -msgstr "Não" +msgstr "Nenhum" #: ../src/gui/debugwindow.cpp:145 msgid "Normal" -msgstr "" +msgstr "Normal" #: ../src/gui/recorder.cpp:91 msgid "Not currently recording." @@ -2347,23 +2242,20 @@ msgstr "Não há gravação neste momento." #: ../src/net/manaserv/charhandler.cpp:139 #: ../src/net/manaserv/charhandler.cpp:220 -#, fuzzy msgid "Not logged in." -msgstr "Já está conectado" +msgstr "Não está logado." #: ../src/net/tmwa/buysellhandler.cpp:108 msgid "Nothing to sell." msgstr "Nada para vender." #: ../src/gui/setup_audio.cpp:97 -#, fuzzy msgid "Notice" -msgstr "Sem texto" +msgstr "Aviso" #: ../src/gui/setup_audio.cpp:51 -#, fuzzy msgid "Notifications volume" -msgstr "Aviso de experiência" +msgstr "Volume das notificações" #: ../src/gui/itemamountwindow.cpp:112 ../src/gui/okdialog.cpp:40 #: ../src/gui/quitdialog.cpp:46 ../src/gui/textdialog.cpp:39 @@ -2376,37 +2268,34 @@ msgid "Ok" msgstr "Ok" #: ../src/net/manaserv/loginhandler.cpp:157 -#, fuzzy msgid "Old email address incorrect." -msgstr "Antigo endereço de email incorrecto" +msgstr "Antigo endereço de email incorreto." #: ../src/net/manaserv/loginhandler.cpp:126 ../src/net/tmwa/loginhandler.cpp:92 -#, fuzzy msgid "Old password incorrect." -msgstr "Senha antiga incorreta" +msgstr "Senha antiga incorreta." #: ../src/gui/socialwindow.cpp:380 ../src/gui/socialwindow.cpp:676 #, c-format msgid "Online (%zu)" -msgstr "" +msgstr "Online (%zu)" #: ../src/gui/widgets/itemlinkhandler.cpp:66 #: ../src/gui/widgets/itemlinkhandler.cpp:95 msgid "Open URL Failed" -msgstr "" +msgstr "Falha ao abrir a URL" #: ../src/gui/widgets/itemlinkhandler.cpp:63 -#, fuzzy msgid "Open URL?" -msgstr "OpenGL" +msgstr "Abrir URL?" #: ../src/gui/setup_video.cpp:228 msgid "OpenGL (Legacy)" -msgstr "" +msgstr "OpenGL (Legado)" #: ../src/gui/widgets/itemlinkhandler.cpp:67 msgid "Opening of URLs requires SDL 2.0.14." -msgstr "" +msgstr "Abertura de URLs requer SDL 2.0.14." #: ../src/commandhandler.h:31 #, c-format @@ -2419,9 +2308,8 @@ msgid "Options:" msgstr "Opções:" #: ../src/resources/userpalette.cpp:98 -#, fuzzy msgid "Other Player Hits Monster" -msgstr "Jogador acerta monstro" +msgstr "Outro jogador acerta monstro" #: ../src/resources/userpalette.cpp:87 msgid "Other Players' Names" @@ -2431,44 +2319,40 @@ msgstr "Nomes de outros jogadores" #: ../src/gui/outfitwindow.cpp:133 #, c-format msgid "Outfit: %d" -msgstr "" +msgstr "Traje: %d" #: ../src/gui/inventorywindow.cpp:109 ../src/gui/outfitwindow.cpp:42 msgid "Outfits" -msgstr "" +msgstr "Trajes" #: ../src/keyboardconfig.cpp:83 -#, fuzzy msgid "Outfits Window" -msgstr "Status" +msgstr "Janela de trajes" #: ../src/gui/setup_interface.cpp:111 -#, fuzzy msgid "Overhead text:" -msgstr "Texto sobrescrito" +msgstr "Texto acima da cabeça:" #: ../src/resources/userpalette.cpp:88 msgid "Own Name" msgstr "Nome Próprio" #: ../src/gui/setup_video.cpp:503 -#, fuzzy msgid "Particle Effect Settings Changed." -msgstr "Configurações de efeito de partícula modificadas." +msgstr "Configurações de Efeito de Partículas Alteradas." #: ../src/resources/userpalette.cpp:94 msgid "Particle Effects" msgstr "Efeitos de partícula" #: ../src/gui/debugwindow.cpp:108 -#, fuzzy, c-format +#, c-format msgid "Particle count: %d" -msgstr "Efeitos de partícula" +msgstr "Contagem de partículas: %d" #: ../src/gui/setup_video.cpp:247 -#, fuzzy msgid "Particle detail:" -msgstr "Detalhe de partículas" +msgstr "Detalhe de partículas:" #: ../src/gui/setup_video.cpp:230 msgid "Particle effects" @@ -2481,29 +2365,31 @@ msgstr "Festa" #: ../src/gui/socialwindow.cpp:200 #, c-format msgid "Party %s quit requested." -msgstr "" +msgstr "Solicitação de saída do grupo %s." #: ../src/resources/userpalette.cpp:92 -#, fuzzy msgid "Party Members" -msgstr "Festa" +msgstr "Membros do grupo" #: ../src/gui/socialwindow.cpp:667 -#, fuzzy msgid "Party Name" -msgstr "Festa" +msgstr "Nome do grupo" #: ../src/net/manaserv/partyhandler.cpp:155 msgid "" "Party invitation rejected by server, because of too many invitations in a " "short time." msgstr "" +"Convite para o grupo rejeitado pelo servidor, devido a convites demais em um " +"curto período de tempo." #: ../src/net/manaserv/partyhandler.cpp:75 #, c-format msgid "" "Party invite failed, because no player called %s is within the visual range." msgstr "" +"Falha no convite para o grupo, porque não há nenhum jogador chamado %s " +"dentro do alcance visual." #: ../src/commandhandler.cpp:428 ../src/net/tmwa/gui/partytab.cpp:102 msgid "Party name is missing." @@ -2514,18 +2400,17 @@ msgid "Party successfully created." msgstr "Grupo criado." #: ../src/gui/beingpopup.cpp:76 -#, fuzzy, c-format +#, c-format msgid "Party: %s" -msgstr "Grupo (%s)" +msgstr "Grupo: %s" #: ../src/client.cpp:845 -#, fuzzy msgid "Password Change" -msgstr "Senha:" +msgstr "Mudança de senha" #: ../src/client.cpp:846 msgid "Password changed successfully!" -msgstr "" +msgstr "Senha alterada com sucesso!" #: ../src/gui/changepassworddialog.cpp:61 ../src/gui/logindialog.cpp:47 #: ../src/gui/register.cpp:68 ../src/gui/unregisterdialog.cpp:51 @@ -2537,9 +2422,9 @@ msgid "Passwords do not match." msgstr "As senhas não coincidem." #: ../src/gui/popupmenu.cpp:186 -#, fuzzy, c-format +#, c-format msgid "Pick up %s" -msgstr "Pegar" +msgstr "Pegar %s" #: ../src/keyboardconfig.cpp:54 msgid "Pickup" @@ -2554,41 +2439,37 @@ msgid "Play" msgstr "Iniciar" #: ../src/net/manaserv/guildhandler.cpp:259 -#, fuzzy, c-format +#, c-format msgid "Player %s kicked you out of guild %s." -msgstr "%s te convidou para entrar no grupo %s." +msgstr "O jogador %s expulsou você da guilda %s." #: ../src/commandhandler.cpp:521 msgid "Player already ignored!" -msgstr "" +msgstr "Jogador já ignorado!" #: ../src/commandhandler.cpp:530 -#, fuzzy msgid "Player could not be ignored!" -msgstr "Impossível enviar sussurro, está ignorado pelo utilizador." +msgstr "O jogador não pôde ser ignorado!" #: ../src/commandhandler.cpp:552 -#, fuzzy msgid "Player could not be unignored!" -msgstr "Impossível enviar sussurro, está ignorado pelo utilizador." +msgstr "Não foi possível deixar de ignorar o jogador!" #: ../src/net/manaserv/charhandler.cpp:211 -#, fuzzy msgid "Player deleted." -msgstr "Personagem apagado." +msgstr "Jogador excluído." #: ../src/commandhandler.cpp:550 msgid "Player no longer ignored!" -msgstr "" +msgstr "Jogador não está mais ignorado!" #: ../src/commandhandler.cpp:528 -#, fuzzy msgid "Player successfully ignored!" -msgstr "Grupo criado." +msgstr "Jogador ignorado com sucesso!" #: ../src/commandhandler.cpp:545 msgid "Player wasn't ignored!" -msgstr "" +msgstr "Jogador não foi ignorado!" #: ../src/gui/setup_players.cpp:229 msgid "Players" @@ -2596,9 +2477,8 @@ msgstr "Jogadores" #: ../src/net/manaserv/chathandler.cpp:194 #: ../src/net/manaserv/chathandler.cpp:285 -#, fuzzy msgid "Players in this channel:" -msgstr "Jogador acerta monstro" +msgstr "Jogadores neste canal:" #: ../src/gui/charcreatedialog.cpp:106 ../src/gui/charcreatedialog.cpp:278 #, c-format @@ -2612,22 +2492,20 @@ msgstr "Por favor remova %d pontos" #: ../src/gui/serverdialog.cpp:316 msgid "Please select a custom server." -msgstr "" +msgstr "Por favor, selecione um servidor personalizado." #: ../src/gui/serverdialog.cpp:272 -#, fuzzy msgid "Please select a valid server." -msgstr "Escolher servidor" +msgstr "Por favor, selecione um servidor válido." #: ../src/commandhandler.cpp:436 ../src/commandhandler.cpp:515 #: ../src/commandhandler.cpp:537 msgid "Please specify a name." -msgstr "" +msgstr "Por favor, especifique um nome." #: ../src/gui/customserverdialog.cpp:167 -#, fuzzy msgid "Please type in at least the address of the server." -msgstr "Por favor escreva o endereço e a porta do servidor." +msgstr "Por favor escreva pelo menos o endereço do servidor." #: ../src/net/tmwa/specialhandler.cpp:212 msgid "Poison had no effect..." @@ -2639,17 +2517,16 @@ msgstr "Porta:" #: ../src/gui/serverdialog.cpp:399 msgid "Preparing download" -msgstr "" +msgstr "Preparando download" #: ../src/gui/chatwindow.cpp:302 -#, fuzzy, c-format +#, c-format msgid "Present: %s; %d players are present." -msgstr "%d jogadores estão presentes." +msgstr "Presente: %s; %d jogadores estão presentes." #: ../src/net/manaserv/beinghandler.cpp:298 -#, fuzzy msgid "Press OK to respawn." -msgstr " Clique em OK para re-popular." +msgstr "Pressione OK para renascer." #: ../src/gui/setup_joystick.cpp:36 ../src/gui/setup_joystick.cpp:70 msgid "Press the button to start calibration" @@ -2667,7 +2544,7 @@ msgstr "Preço: %s / Total: %s" #: ../src/playerrelations.cpp:330 msgid "Print '...'" -msgstr "" +msgstr "Imprimir '...'" #: ../src/gui/tradewindow.cpp:53 msgid "Propose trade" @@ -2680,14 +2557,14 @@ msgstr "Pulsar" #: ../src/gui/setup_players.cpp:223 msgid "Put all whispers in tabs" -msgstr "Deixar todos os sussurros em abas" +msgstr "Colocar todos os sussurros em abas" #: ../src/gui/buydialog.cpp:78 ../src/gui/quitdialog.cpp:40 #: ../src/gui/quitdialog.cpp:42 ../src/gui/quitdialog.cpp:43 #: ../src/gui/selldialog.cpp:78 ../src/gui/serverdialog.cpp:190 #: ../src/keyboardconfig.cpp:104 msgid "Quit" -msgstr "Sair" +msgstr "Encerrar" #: ../src/gui/setup_colors.cpp:80 ../src/gui/setup_colors.cpp:81 #: ../src/gui/setup_colors.cpp:321 @@ -2695,9 +2572,8 @@ msgid "Rainbow" msgstr "Arco-Íris" #: ../src/gui/socialwindow.cpp:596 -#, fuzzy msgid "Received guild request, but one already exists." -msgstr "Requisição de grupo recebida, mas já existe um." +msgstr "Requisição de guilda recebida, mas já existe uma." #: ../src/gui/socialwindow.cpp:617 msgid "Received party request, but one already exists." @@ -2708,9 +2584,8 @@ msgid "Recording..." msgstr "Gravando..." #: ../src/gui/setup_colors.cpp:102 -#, fuzzy msgid "Red:" -msgstr "Vermelho: " +msgstr "Vermelho:" #: ../src/gui/logindialog.cpp:53 ../src/gui/register.cpp:58 #: ../src/gui/register.cpp:73 @@ -2718,33 +2593,29 @@ msgid "Register" msgstr "Registo" #: ../src/gui/logindialog.cpp:119 -#, fuzzy msgid "Registration disabled" -msgstr "Partilha de itens desabilitado." +msgstr "Registro desativado" #: ../src/net/tmwa/loginhandler.cpp:169 -#, fuzzy msgid "Rejected from server." -msgstr "Rejeitado pelo servidor" +msgstr "Rejeitado pelo servidor." #: ../src/gui/socialwindow.cpp:509 -#, fuzzy msgid "Rejected guild invite." -msgstr "Rejeitar convite de %s." +msgstr "Convite para guilda rejeitado." #: ../src/gui/socialwindow.cpp:491 -#, fuzzy, c-format +#, c-format msgid "Rejected party invite from %s." -msgstr "Rejeitar convite de %s." +msgstr "Convite para grupo de %s rejeitado." #: ../src/gui/setup_players.cpp:56 msgid "Relation" msgstr "Relação" #: ../src/gui/logindialog.cpp:52 -#, fuzzy msgid "Remember username" -msgstr "Lembras nome de usuário" +msgstr "Lembrar usuário" #: ../src/net/manaserv/tradehandler.cpp:115 #: ../src/net/tmwa/tradehandler.cpp:109 @@ -2752,18 +2623,16 @@ msgid "Request for Trade" msgstr "Proposta de negociação" #: ../src/net/tmwa/gamehandler.cpp:89 -#, fuzzy msgid "Request to quit denied!" -msgstr "Proposta de negociação" +msgstr "Solicitação de saída negada!" #: ../src/client.cpp:733 -#, fuzzy msgid "Requesting characters" -msgstr "Seleccione um Personagem" +msgstr "Solicitando personagens" #: ../src/client.cpp:817 msgid "Requesting registration details" -msgstr "" +msgstr "Solicitando detalhes de registro" #: ../src/commandhandler.cpp:416 #, c-format @@ -2779,9 +2648,8 @@ msgid "Reset Windows" msgstr "Reiniciar Janelas" #: ../src/gui/setup_video.cpp:313 -#, fuzzy msgid "Resolution:" -msgstr "Relação" +msgstr "Resolução:" #: ../src/gui/inventorywindow.cpp:132 ../src/gui/popupmenu.cpp:389 msgid "Retrieve" @@ -2796,23 +2664,20 @@ msgid "Return toggles chat." msgstr "Enter alterna para o chat." #: ../src/net/tmwa/inventoryhandler.h:74 -#, fuzzy msgid "Ring 1/2" -msgstr "Anéis" +msgstr "Anel 1/2" #: ../src/net/tmwa/inventoryhandler.h:76 -#, fuzzy msgid "Ring 2/2" -msgstr "Anéis" +msgstr "Anel 2/2" #: ../src/gui/setup_joystick.cpp:76 msgid "Rotate the stick" msgstr "Rode o manipulo" #: ../src/gui/setup_audio.cpp:50 -#, fuzzy msgid "SFX volume" -msgstr "Volume dos Efeitos" +msgstr "Volume de efeitos sonoros" #: ../src/net/manaserv/beinghandler.cpp:290 #: ../src/net/tmwa/playerhandler.cpp:109 @@ -2825,16 +2690,16 @@ msgstr "Erro ao salvar screenshot!" #: ../src/gui/setup_video.cpp:315 msgid "Scale:" -msgstr "" +msgstr "Escala:" #: ../src/keyboardconfig.cpp:57 msgid "Screenshot" msgstr "Captura de Ecrã" #: ../src/game.cpp:328 -#, fuzzy, c-format +#, c-format msgid "Screenshot saved as %s" -msgstr "Screenshot salvo em ~/" +msgstr "Captura de tela salva como %s" #: ../src/keyboardconfig.cpp:100 msgid "Scroll Chat Down" @@ -2846,7 +2711,7 @@ msgstr "Rolar janela de chat para cima" #: ../src/gui/inventorywindow.cpp:87 msgid "Search:" -msgstr "" +msgstr "Pesquisar:" #: ../src/net/tmwa/specialhandler.cpp:182 msgid "Seems you need more money... ;-)" @@ -2857,9 +2722,8 @@ msgid "Select OK" msgstr "Seleccionar OK" #: ../src/gui/worldselectdialog.cpp:68 -#, fuzzy msgid "Select World" -msgstr "Seleccionar OK" +msgstr "Selecionar Mundo" #: ../src/gui/itemamountwindow.cpp:143 msgid "Select amount of items to drop." @@ -2882,9 +2746,8 @@ msgid "Select amount of items to trade." msgstr "Seleccionar a quantidade de itens a negociar." #: ../src/net/manaserv/charhandler.cpp:223 -#, fuzzy msgid "Selection out of range." -msgstr "Seleccionar a quantidade de itens a negociar." +msgstr "Seleção fora de alcance." #: ../src/gui/buyselldialog.cpp:47 ../src/gui/selldialog.cpp:50 #: ../src/gui/selldialog.cpp:77 @@ -2897,16 +2760,15 @@ msgstr "Enviar" #: ../src/net/tmwa/loginhandler.cpp:186 msgid "Server overpopulated." -msgstr "" +msgstr "Servidor superpovoado." #: ../src/net/net.cpp:165 msgid "Server protocol unsupported" -msgstr "" +msgstr "Protocolo do servidor não suportado" #: ../src/gui/customserverdialog.cpp:60 -#, fuzzy msgid "Server type:" -msgstr "Servidor:" +msgstr "Tipo de servidor:" #: ../src/gui/widgets/chattab.cpp:175 msgid "Server:" @@ -2925,41 +2787,36 @@ msgid "Shop" msgstr "Loja" #: ../src/gui/windowmenu.cpp:69 -#, fuzzy msgid "Shortcuts" -msgstr "Atalho" +msgstr "Atalhos" #: ../src/commandhandler.cpp:482 ../src/commandhandler.cpp:491 msgid "Show IP: Off" -msgstr "" +msgstr "Exibir IP: Desligado" #: ../src/commandhandler.cpp:482 ../src/commandhandler.cpp:495 msgid "Show IP: On" -msgstr "" +msgstr "Exibir IP: Ligado" #: ../src/gui/setup_interface.cpp:108 -#, fuzzy msgid "Show damage" -msgstr "Mostrar nome" +msgstr "Mostrar dano" #: ../src/gui/setup_players.cpp:225 -#, fuzzy msgid "Show gender" -msgstr "Mostrar nome" +msgstr "Mostrar gênero" #: ../src/gui/setup_interface.cpp:90 -#, fuzzy msgid "Show own name" -msgstr "Mostrar nome" +msgstr "Mostrar o próprio nome" #: ../src/gui/setup_interface.cpp:92 -#, fuzzy msgid "Show pickup notification:" -msgstr "Mostrar aviso de achado" +msgstr "Mostrar notificação de coleta:" #: ../src/gui/debugwindow.cpp:134 msgid "Show:" -msgstr "" +msgstr "Exibir:" #: ../src/keyboardconfig.cpp:56 msgid "Sit" @@ -2970,27 +2827,27 @@ msgid "Sit failed!" msgstr "Falha ao sentar!" #: ../src/gui/skilldialog.cpp:375 -#, fuzzy, c-format +#, c-format msgid "Skill %d" -msgstr "Competências" +msgstr "Habilidade %d" #: ../src/gui/skilldialog.cpp:366 -#, fuzzy, c-format +#, c-format msgid "Skill Set %d" -msgstr "Pontos de habilidade: %d" +msgstr "Conjunto de habilidades %d" #: ../src/keyboardconfig.cpp:75 msgid "Skill Window" -msgstr "Janela de Habilidade" +msgstr "Janela de Habilidades" #: ../src/gui/skilldialog.cpp:265 -#, fuzzy, c-format +#, c-format msgid "Skill points available: %d" -msgstr "Pontos de habilidade: %d" +msgstr "Pontos de habilidade disponíveis: %d" #: ../src/gui/skilldialog.cpp:205 ../src/gui/windowmenu.cpp:61 msgid "Skills" -msgstr "Competências" +msgstr "Habilidades" #: ../src/gui/inventorywindow.cpp:86 msgid "Slots:" @@ -3006,17 +2863,15 @@ msgstr "Emoticons" #: ../src/gui/socialwindow.cpp:350 ../src/gui/windowmenu.cpp:67 msgid "Social" -msgstr "" +msgstr "Social" #: ../src/keyboardconfig.cpp:81 -#, fuzzy msgid "Social Window" -msgstr "Janela de Habilidade" +msgstr "Janela Social" #: ../src/net/tmwa/generalhandler.cpp:137 -#, fuzzy msgid "Someone else is trying to use this account." -msgstr "Mais alguém está tentando utilizar esta conta" +msgstr "Alguém está tentando utilizar esta conta." #: ../src/gui/setup_audio.cpp:42 msgid "Sound" @@ -3024,27 +2879,27 @@ msgstr "Som" #: ../src/gui/setup_audio.cpp:109 msgid "Sound Engine" -msgstr "" +msgstr "Motor de Som" #: ../src/gui/debugwindow.cpp:146 msgid "Special 1" -msgstr "" +msgstr "Especial 1" #: ../src/gui/debugwindow.cpp:147 msgid "Special 2" -msgstr "" +msgstr "Especial 2" #: ../src/gui/debugwindow.cpp:148 msgid "Special 3" -msgstr "" +msgstr "Especial 3" #: ../src/gui/specialswindow.cpp:69 ../src/gui/windowmenu.cpp:65 msgid "Specials" -msgstr "" +msgstr "Especiais" #: ../src/gui/debugwindow.cpp:144 msgid "Specials:" -msgstr "" +msgstr "Especiais:" #: ../src/gui/setup_colors.cpp:82 ../src/gui/setup_colors.cpp:83 #: ../src/gui/setup_colors.cpp:321 @@ -3052,9 +2907,8 @@ msgid "Spectrum" msgstr "Espectro" #: ../src/net/tmwa/generalhandler.cpp:143 -#, fuzzy msgid "Speed hack detected." -msgstr "Hack de velocidade detectado" +msgstr "Hack de velocidade detectado." #: ../src/gui/inventorywindow.cpp:108 ../src/gui/popupmenu.cpp:382 msgid "Split" @@ -3062,7 +2916,7 @@ msgstr "Dividir" #: ../src/localplayer.cpp:868 msgid "Stack is too big." -msgstr "" +msgstr "Pilha muito grande." #: ../src/gui/recorder.cpp:104 msgid "Starting to record..." @@ -3105,9 +2959,9 @@ msgid "Strength" msgstr "Força" #: ../src/resources/attributes.cpp:165 -#, fuzzy, c-format +#, c-format msgid "Strength %+.1f" -msgstr "Força %+d" +msgstr "Força %+.1f" #: ../src/net/tmwa/generalhandler.cpp:99 #, c-format @@ -3124,7 +2978,7 @@ msgstr "Enviar" #: ../src/gui/charselectdialog.cpp:120 msgid "Switch Login" -msgstr "" +msgstr "Alterar login" #: ../src/gui/quitdialog.cpp:45 msgid "Switch character" @@ -3135,35 +2989,33 @@ msgid "Switch server" msgstr "Mudar de servidor" #: ../src/gui/debugwindow.cpp:252 -#, fuzzy msgid "Switches" -msgstr "Mudar de servidor" +msgstr "Troca" #: ../src/keyboardconfig.cpp:49 msgid "Talk" msgstr "Falar" #: ../src/gui/popupmenu.cpp:149 -#, fuzzy, c-format +#, c-format msgid "Talk to %s" -msgstr "@@talk|Falar com %s@@" +msgstr "Falar com %s" #: ../src/keyboardconfig.cpp:47 msgid "Target & Attack" -msgstr "Selecionar & Atacar" +msgstr "Mirar & Atacar" #: ../src/keyboardconfig.cpp:51 -#, fuzzy msgid "Target Monster" -msgstr "Seleccionar o mais próximo" +msgstr "Mirar monstro" #: ../src/keyboardconfig.cpp:52 msgid "Target NPC" -msgstr "Seleccionar NPC" +msgstr "Mirar NPC" #: ../src/keyboardconfig.cpp:53 msgid "Target Player" -msgstr "Seleccionar Jogador" +msgstr "Mirar Jogador" #: ../src/gui/setup_interface.cpp:72 msgid "Text" @@ -3175,43 +3027,40 @@ msgid "The cold hands of the grim reaper are grabbing for your soul." msgstr "As mãos frias da morte estão levando sua alma." #: ../src/game.cpp:366 -#, fuzzy msgid "The connection to the server was lost." -msgstr "Conexão com o servidor perdida, o jogo será fechado" +msgstr "A conexão com o servidor foi perdida." #: ../src/gui/changeemaildialog.cpp:141 -#, fuzzy msgid "The email address entries mismatch." -msgstr "O novo endereço de email já existe." +msgstr "Os endereços de e-mail não correspondem." #: ../src/net/manaserv/loginhandler.cpp:163 -#, fuzzy msgid "The new email address already exists." msgstr "O novo endereço de email já existe." #: ../src/gui/changeemaildialog.cpp:127 -#, fuzzy, c-format +#, c-format msgid "The new email address needs to be at least %d characters long." -msgstr "O nome de utilizador necessita de pelo menos %d caracteres." +msgstr "O novo endereço de e-mail precisa ter pelo menos %d caracteres." #: ../src/gui/changeemaildialog.cpp:134 -#, fuzzy, c-format +#, c-format msgid "The new email address needs to be less than %d characters long." -msgstr "O nome de utilizador só pode ter %d caracteres." +msgstr "O novo endereço de e-mail precisa ter menos de %d caracteres." #: ../src/gui/changepassworddialog.cpp:130 msgid "The new password entries mismatch." -msgstr "" +msgstr "As entradas da nova senha não coincidem." #: ../src/gui/changepassworddialog.cpp:116 -#, fuzzy, c-format +#, c-format msgid "The new password needs to be at least %d characters long." -msgstr "A password necessita de pelo menos %d caracteres." +msgstr "A nova senha precisa ter pelo menos %d caracteres." #: ../src/gui/changepassworddialog.cpp:123 -#, fuzzy, c-format +#, c-format msgid "The new password needs to be less than %d characters long." -msgstr "A password só pode ter até %d caracteres." +msgstr "A nova senha precisa ter menos de %d caracteres." #: ../src/gui/register.cpp:182 ../src/gui/unregisterdialog.cpp:114 #, c-format @@ -3234,14 +3083,12 @@ msgid "The username needs to be less than %d characters long." msgstr "O nome de utilizador só pode ter %d caracteres." #: ../src/net/tmwa/generalhandler.cpp:140 -#, fuzzy msgid "This account is already logged in." -msgstr "Existe alguém logado a esta conta" +msgstr "Esta conta já está logada." #: ../src/net/tmwa/gui/guildtab.cpp:73 -#, fuzzy msgid "This command causes the player to leave the guild." -msgstr "Este comando faz com que o jogador saia do grupo." +msgstr "Este comando faz com que o jogador saia da guilda." #: ../src/net/tmwa/gui/partytab.cpp:74 msgid "This command causes the player to leave the party." @@ -3256,9 +3103,8 @@ msgid "This command changes the party's item sharing policy." msgstr "Este comando muda a opção de partilha de itens no grupo." #: ../src/commandhandler.cpp:255 -#, fuzzy msgid "This command clears the away status and message." -msgstr "Define <mensagem> como o tópico." +msgstr "Este comando remove o status de ausente e a mensagem." #: ../src/commandhandler.cpp:209 msgid "This command clears the chat log of previous chat." @@ -3266,20 +3112,19 @@ msgstr "Limpa os logs do chat anterior." #: ../src/gui/widgets/whispertab.cpp:84 msgid "This command closes the current whisper tab." -msgstr "Este comando fecha a atual aba de sussurros" +msgstr "Este comando fecha a aba de sussurro atual." #: ../src/commandhandler.cpp:260 -#, fuzzy msgid "This command creates a new party called <name>." -msgstr "Estes comandos criam um novo grupo chamado <nome-do-grupo>." +msgstr "Este comando cria um novo grupo chamado <nome>." #: ../src/commandhandler.cpp:197 msgid "This command displays a list of all commands available." -msgstr "Este comando mostra a lista de todos os comandos disponiveis" +msgstr "Este comando mostra a lista de todos os comandos disponíveis." #: ../src/commandhandler.cpp:200 msgid "This command displays help on <command>." -msgstr "Exibe o conteúdo de ajuda de <command>" +msgstr "Exibe o conteúdo de ajuda de <command>." #: ../src/commandhandler.cpp:304 msgid "This command displays the name of the current map." @@ -3315,23 +3160,23 @@ msgstr "" "gravação." #: ../src/commandhandler.cpp:214 -#, fuzzy msgid "This command ignores the given player regardless of current relations." -msgstr "Mostra o número de jogadores conectados." +msgstr "" +"Este comando ignora o jogador informado, independentemente das relações " +"atuais." #: ../src/gui/widgets/whispertab.cpp:89 -#, fuzzy msgid "This command ignores the other player regardless of current relations." -msgstr "Mostra o número de jogadores conectados." +msgstr "" +"Este comando ignora o outro jogador, independentemente das relações atuais." #: ../src/commandhandler.cpp:265 ../src/net/tmwa/gui/partytab.cpp:67 msgid "This command invites <nick> to party with you." msgstr "Convida <nick> para uma festa com você." #: ../src/net/tmwa/gui/guildtab.cpp:66 -#, fuzzy msgid "This command invites <nick> to the guild you're in." -msgstr "Convida <nick> para uma festa com você." +msgstr "Este comando convida <nick> para a guilda em que você está." #: ../src/gui/widgets/channeltab.cpp:73 msgid "This command leaves the current channel." @@ -3382,13 +3227,13 @@ msgstr "" #: ../src/commandhandler.cpp:298 msgid "This command stops ignoring the given player if they are being ignored" msgstr "" +"Este comando para de ignorar o jogador especificado, se ele estiver sendo " +"ignorado" #: ../src/gui/widgets/whispertab.cpp:95 -#, fuzzy msgid "This command stops ignoring the other player if they are being ignored." msgstr "" -"Este comando inicia a gravação do registo do chat para o ficheiro " -"<nome_do_ficheiro>." +"Este comando para de ignorar o outro jogador, caso ele esteja sendo ignorado." #: ../src/commandhandler.cpp:231 msgid "This command tell others you are (doing) <msg>." @@ -3397,21 +3242,20 @@ msgstr "Este comando diz aos outros o que eu estou (fazendo) <msg>." #: ../src/commandhandler.cpp:252 msgid "This command tells you're away from keyboard with the given reason." msgstr "" +"Este comando indica que você está afastado do teclado com o motivo " +"especificado." #: ../src/commandhandler.cpp:246 -#, fuzzy msgid "This command tries to make a tab for whispers between you and <nick>." -msgstr "" -"Este comando cria uma aba para mensagens confidenciais entre você e <nick>." +msgstr "Este comando tenta criar uma aba para os sussurros entre você e <nick>." #: ../src/gui/setup_colors.cpp:43 msgid "This is what the color looks like" msgstr "A cor se parece com isso" #: ../src/net/tmwa/loginhandler.cpp:189 -#, fuzzy msgid "This user name is already taken." -msgstr "Este nome de utilizador já está em uso" +msgstr "Este nome de usuário já está em uso." #: ../src/gui/setup_interface.cpp:44 msgid "Tiny" @@ -3434,7 +3278,7 @@ msgstr "Tópico: %s" #: ../src/net/tmwa/inventoryhandler.h:64 msgid "Torso" -msgstr "" +msgstr "Tronco" #: ../src/gui/tradewindow.cpp:73 ../src/gui/tradewindow.cpp:74 msgid "Trade" @@ -3464,9 +3308,9 @@ msgid "Trade with %s cancelled." msgstr "Negociação com %s cancelada." #: ../src/gui/popupmenu.cpp:79 -#, fuzzy, c-format +#, c-format msgid "Trade with %s..." -msgstr "Negociando com %s" +msgstr "Negociar com %s..." #: ../src/gui/tradewindow.cpp:59 msgid "Trade: You" @@ -3491,37 +3335,32 @@ msgid "Trading with %s" msgstr "Negociando com %s" #: ../src/gui/setup_video.cpp:402 -#, fuzzy msgid "Transparency disabled" -msgstr "Partilha de experiência desabilitado." +msgstr "Transparência desativada" #: ../src/gui/setup_video.cpp:410 msgid "Transparency enabled" -msgstr "" +msgstr "Transparência ativada" #: ../src/localplayer.cpp:864 -#, fuzzy msgid "Tried to pick up nonexistent item." -msgstr "Impossível pegar item." +msgstr "Tentou pegar um item inexistente." #: ../src/commandhandler.cpp:315 msgid "Type /help for a list of commands." msgstr "Digite /help para ver uma lista de comandos." #: ../src/gui/changeemaildialog.cpp:51 -#, fuzzy msgid "Type new email address twice:" msgstr "Digite o novo endereço de email duas vezes:" #: ../src/gui/changepassworddialog.cpp:63 -#, fuzzy msgid "Type new password twice:" msgstr "Digite a nova senha duas vezes:" #: ../src/gui/setup_colors.cpp:65 -#, fuzzy msgid "Type:" -msgstr "Tipo: " +msgstr "Tipo:" #: ../src/net/tmwa/buysellhandler.cpp:118 msgid "Unable to buy." @@ -3532,9 +3371,9 @@ msgid "Unable to equip." msgstr "Impossível equipar." #: ../src/net/tmwa/network.cpp:470 -#, fuzzy, c-format +#, c-format msgid "Unable to resolve host \"%s\"" -msgstr "Impossibilitado de vender." +msgstr "Não foi possível resolver o host \"%s\"" #: ../src/net/tmwa/buysellhandler.cpp:124 msgid "Unable to sell." @@ -3545,9 +3384,8 @@ msgid "Unable to unequip." msgstr "Impossível desequipar." #: ../src/gui/setup_keyboard.cpp:93 -#, fuzzy msgid "Unassign" -msgstr "Associar" +msgstr "Desatribuir" #: ../src/gui/equipmentwindow.cpp:71 ../src/gui/inventorywindow.cpp:94 #: ../src/gui/inventorywindow.cpp:372 ../src/gui/popupmenu.cpp:365 @@ -3555,14 +3393,13 @@ msgid "Unequip" msgstr "Desequipar" #: ../src/gui/outfitwindow.cpp:53 -#, fuzzy msgid "Unequip first" -msgstr "Desequipar" +msgstr "Desequipar primeiro" #: ../src/net/manaserv/charhandler.cpp:271 #, c-format msgid "Unhandled character select error message %i." -msgstr "" +msgstr "Mensagem de erro não tratada na seleção de personagem %i." #: ../src/net/tmwa/tradehandler.cpp:156 msgid "Unhandled trade cancel packet." @@ -3571,36 +3408,32 @@ msgstr "Troca injusta pacote cancelado." #: ../src/gui/popupmenu.cpp:110 ../src/gui/popupmenu.cpp:119 #, c-format msgid "Unignore %s" -msgstr "" +msgstr "Deixar de ignorar %s" #: ../src/net/net.cpp:140 -#, fuzzy msgid "Unknown Server Type! Exiting." -msgstr "Tipo de item desconhecido" +msgstr "Tipo de servidor desconhecido! Saindo." #: ../src/net/manaserv/chathandler.cpp:350 -#, fuzzy msgid "Unknown channel event." -msgstr "Comando desconhecido" +msgstr "Evento de canal desconhecido." #: ../src/net/tmwa/charserverhandler.cpp:112 -#, fuzzy msgid "Unknown char-server failure." -msgstr "Erro desconhecido" +msgstr "Falha desconhecida no servidor de personagens." #: ../src/commandhandler.cpp:128 ../src/commandhandler.cpp:314 msgid "Unknown command." -msgstr "Comando desconhecido" +msgstr "Comando desconhecido." #: ../src/net/tmwa/generalhandler.cpp:149 -#, fuzzy msgid "Unknown connection error." -msgstr "Erro de conexão desconhecido" +msgstr "Erro de conexão desconhecido." #: ../src/net/manaserv/charhandler.cpp:226 -#, fuzzy, c-format +#, c-format msgid "Unknown error (%d)." -msgstr "Erro desconhecido" +msgstr "Erro desconhecido (%d)." #: ../src/net/manaserv/charhandler.cpp:175 #: ../src/net/manaserv/loginhandler.cpp:101 @@ -3609,9 +3442,8 @@ msgstr "Erro desconhecido" #: ../src/net/manaserv/loginhandler.cpp:290 #: ../src/net/manaserv/loginhandler.cpp:327 ../src/net/tmwa/loginhandler.cpp:98 #: ../src/net/tmwa/loginhandler.cpp:195 -#, fuzzy msgid "Unknown error." -msgstr "Erro desconhecido" +msgstr "Erro desconhecido." #: ../src/net/tmwa/partyhandler.cpp:131 #, c-format @@ -3623,9 +3455,8 @@ msgid "Unknown item" msgstr "Item desconhecido" #: ../src/localplayer.cpp:871 -#, fuzzy msgid "Unknown problem picking up item." -msgstr "Impossível pegar item." +msgstr "Problema desconhecido ao pegar o item." #: ../src/gui/charselectdialog.cpp:134 ../src/gui/unregisterdialog.cpp:45 #: ../src/gui/unregisterdialog.cpp:53 @@ -3633,14 +3464,12 @@ msgid "Unregister" msgstr "Remover o Registo" #: ../src/client.cpp:884 -#, fuzzy msgid "Unregister Successful" -msgstr "Remover o Registo" +msgstr "Remoção de registro bem-sucedido" #: ../src/net/tmwa/loginhandler.cpp:160 -#, fuzzy msgid "Unregistered ID." -msgstr "ID não registado" +msgstr "ID não registrado." #: ../src/gui/skilldialog.cpp:220 msgid "Up" @@ -3655,18 +3484,16 @@ msgid "Use" msgstr "Usar" #: ../src/net/manaserv/loginhandler.cpp:317 -#, fuzzy msgid "Username already exists." -msgstr "Nome de utilizador já existe" +msgstr "Nome de usuário já existe." #: ../src/net/tmwa/loginhandler.cpp:192 -#, fuzzy msgid "Username permanently erased." -msgstr "Nome de utilizador já existe" +msgstr "Nome de usuário excluído permanentemente." #: ../src/gui/setup_video.cpp:227 msgid "VSync" -msgstr "" +msgstr "VSync" #: ../src/gui/setup_video.cpp:244 msgid "Video" @@ -3681,9 +3508,9 @@ msgid "Vitality" msgstr "Vitalidade" #: ../src/resources/attributes.cpp:201 -#, fuzzy, c-format +#, c-format msgid "Vitality %+.1f" -msgstr "Vitalidade %+d" +msgstr "Vitalidade %+.1f" #: ../src/net/tmwa/generalhandler.cpp:101 #, c-format @@ -3699,9 +3526,8 @@ msgid "Waiting for server" msgstr "Aguardando servidor" #: ../src/gui/serverdialog.cpp:395 -#, fuzzy msgid "Waiting for server..." -msgstr "Aguardando servidor" +msgstr "Aguardando servidor..." #: ../src/net/tmwa/specialhandler.cpp:206 msgid "Warp failed..." @@ -3714,108 +3540,99 @@ msgstr "Lamentamos informar que seu personagem foi morto em combate." #: ../src/keyboardconfig.cpp:84 msgid "Wear Outfit" -msgstr "" +msgstr "Usar Traje" #: ../src/gui/inventorywindow.cpp:111 msgid "Weight:" msgstr "Peso:" #: ../src/gui/itempopup.cpp:184 -#, fuzzy, c-format +#, c-format msgid "Weight: %s" -msgstr "Peso: " +msgstr "Peso: %s" #: ../src/gui/setup_players.cpp:254 msgid "When ignoring:" msgstr "Quando ignorado:" #: ../src/gui/popupmenu.cpp:87 -#, fuzzy, c-format +#, c-format msgid "Whisper %s" -msgstr "Sussurrar" +msgstr "Sussurrar %s" #: ../src/net/tmwa/chathandler.cpp:90 -#, fuzzy, c-format +#, c-format msgid "Whisper could not be sent, %s is offline." -msgstr "Impossível enviar sussurro, o utilizador está desconectado." +msgstr "O sussurro não pôde ser enviado, %s está offline." #: ../src/net/tmwa/chathandler.cpp:99 -#, fuzzy, c-format +#, c-format msgid "Whisper could not be sent, ignored by %s." -msgstr "Impossível enviar sussurro, está ignorado pelo utilizador." +msgstr "O sussurro não pôde ser enviado, ignorado por %s." #: ../src/gui/chatwindow.cpp:497 #, c-format msgid "Whispering to %s: %s" -msgstr "A sussurrar para %s: %s" +msgstr "Sussurrando para %s: %s" #: ../src/gui/socialwindow.cpp:144 #, c-format msgid "Who would you like to invite to guild %s?" -msgstr "" +msgstr "Quem você gostaria de convidar para a guilda %s?" #: ../src/gui/socialwindow.cpp:215 #, c-format msgid "Who would you like to invite to party %s?" -msgstr "" +msgstr "Quem você gostaria de convidar para o grupo %s?" #: ../src/resources/attributes.cpp:219 -#, fuzzy msgid "Willpower" -msgstr "Força de Vontade:" +msgstr "Vontade" #: ../src/resources/attributes.cpp:225 -#, fuzzy, c-format +#, c-format msgid "Willpower %+.1f" -msgstr "Força de vontade %+d" +msgstr "Vontade %+.1f" #: ../src/gui/setup_video.cpp:311 -#, fuzzy msgid "Window mode:" -msgstr " modo de video: " +msgstr "Modo de janela:" #: ../src/gui/setup_video.cpp:221 -#, fuzzy msgid "Windowed" -msgstr "em janela" +msgstr "Em janela" #: ../src/gui/setup_video.cpp:221 -#, fuzzy msgid "Windowed Fullscreen" -msgstr "Ecrã completo" +msgstr "Tela cheia em janela" #: ../src/net/manaserv/loginhandler.cpp:92 -#, fuzzy msgid "Wrong magic_token." -msgstr "Simbolo-mágico errado." +msgstr "Token mágico incorreto." #: ../src/net/tmwa/loginhandler.cpp:163 -#, fuzzy msgid "Wrong password." -msgstr "Senha incorreta" +msgstr "Senha incorreta." #: ../src/net/manaserv/loginhandler.cpp:277 -#, fuzzy msgid "Wrong username or password." -msgstr "Nome de utilizador ou senha inválida" +msgstr "Nome de usuário ou senha incorretos." #: ../src/net/manaserv/loginhandler.cpp:314 -#, fuzzy msgid "Wrong username, password or email address." -msgstr "Nome de utilizador, senha ou email inválido" +msgstr "Nome de usuário, senha ou endereço de email incorretos." #: ../src/gui/confirmdialog.cpp:40 msgid "Yes" msgstr "Sim" #: ../src/net/manaserv/beinghandler.cpp:299 -#, fuzzy msgid "You Died" msgstr "Você morreu" #: ../src/net/tmwa/playerhandler.cpp:130 msgid "You are an ex-player." -msgstr "Você é um ex-jogador" +msgstr "Você é um ex-jogador." #: ../src/net/tmwa/playerhandler.cpp:254 msgid "" @@ -3839,9 +3656,8 @@ msgid "You are not that alive anymore." msgstr "Você não está mais vivo." #: ../src/net/tmwa/partyhandler.cpp:328 -#, fuzzy msgid "You can only invite when you are in a party!" -msgstr "%s te convidou para entrar no seu grupo." +msgstr "Você só pode convidar quando estiver em um grupo!" #: ../src/net/tmwa/specialhandler.cpp:179 msgid "You cannot do that right now!" @@ -3856,7 +3672,7 @@ msgid "You don't have enough money." msgstr "Você não tem dinheiro suficiente." #: ../src/gui/tradewindow.cpp:98 ../src/gui/tradewindow.cpp:134 -#, fuzzy, c-format +#, c-format msgid "You get %s" msgstr "Você obteve %s" @@ -3865,22 +3681,20 @@ msgid "You give:" msgstr "Dá:" #: ../src/gui/socialwindow.cpp:630 -#, fuzzy, c-format +#, c-format msgid "You have been invited to join the %s party." -msgstr "%s te convidou para entrar no grupo %s." +msgstr "Você foi convidado para entrar no grupo %s." #: ../src/gui/socialwindow.cpp:626 -#, fuzzy msgid "You have been invited you to join a party." -msgstr "%s te convidou para entrar no seu grupo." +msgstr "Você foi convidado para entrar em um grupo." #: ../src/net/tmwa/loginhandler.cpp:172 -#, fuzzy msgid "" "You have been permanently banned from the game. Please contact the GM team." msgstr "" -"Você foi permanentemente banido do jogo. Por favor entre em contacto com " -"algum GM." +"Você foi banido permanentemente do jogo. Por favor, entre em contato com a " +"equipe de GM." #: ../src/net/tmwa/loginhandler.cpp:179 #, c-format @@ -3909,11 +3723,11 @@ msgstr "Você ainda não tem nível necessário!" #: ../src/gui/setup_audio.cpp:97 msgid "You may have to restart your client if you want to download new music" -msgstr "" +msgstr "Você pode precisar reiniciar seu cliente se quiser baixar novas músicas" #: ../src/gui/setup_video.cpp:403 ../src/gui/setup_video.cpp:411 msgid "You must restart to apply changes." -msgstr "" +msgstr "Você precisa reiniciar para aplicar as alterações." #: ../src/net/tmwa/specialhandler.cpp:191 msgid "You need another blue gem!" @@ -3925,19 +3739,19 @@ msgstr "Você precisa de outra gema vermelha!" #: ../src/gui/logindialog.cpp:119 msgid "You need to use the website to register an account for this server." -msgstr "" +msgstr "Você precisa usar o site para registrar uma conta para este servidor." #: ../src/localplayer.cpp:889 -#, fuzzy, c-format +#, c-format msgid "You picked up %d [@@%d|%s@@]." msgid_plural "You picked up %d [@@%d|%s@@]." -msgstr[0] "Você pegou %s [@@%d|%s@@]." -msgstr[1] "Você pegou %s [@@%d|%s@@]." +msgstr[0] "Você pegou %d [@@%d|%s@@]." +msgstr[1] "Você pegou %d [@@%d|%s@@]." #: ../src/net/tmwa/playerhandler.cpp:326 -#, fuzzy, c-format +#, c-format msgid "You picked up %s." -msgstr "Você pegou " +msgstr "Você pegou %s." #: ../src/net/manaserv/beinghandler.cpp:293 #: ../src/net/tmwa/playerhandler.cpp:115 @@ -3947,7 +3761,7 @@ msgstr "Você estragou tudo de novo, jogue fora seu corpo e arranje outro." #: ../src/net/manaserv/loginhandler.cpp:323 msgid "You took too long with the captcha or your response was incorrect." -msgstr "" +msgstr "Você demorou demais com o captcha ou sua resposta estava incorreta." #: ../src/net/tmwa/playerhandler.cpp:122 msgid "You're a stiff." @@ -3980,7 +3794,7 @@ msgstr "Você chutou o balde." #: ../src/net/tmwa/playerhandler.cpp:128 msgid "" "You've shuffled off your mortal coil, run down the curtain and joined the " -"bleedin' choir invisibile." +"bleedin' choir invisible." msgstr "" "Você dispensou seu corpo mortal, abaixou as cortinas e juntou-se ao maldito " "coro invisível." @@ -3991,7 +3805,7 @@ msgstr "Seus processos metabólicos são história agora." #: ../src/gui/charcreatedialog.cpp:199 msgid "Your name needs to be at least 4 characters." -msgstr "O seu nome necessita de pelo menos 4 caracteres" +msgstr "O seu nome necessita de pelo menos 4 caracteres." #: ../src/net/manaserv/beinghandler.cpp:286 #: ../src/net/tmwa/playerhandler.cpp:103 @@ -4004,7 +3818,7 @@ msgstr "" #: ../src/main.cpp:50 msgid "[mana-file] : The mana file is an XML file (.mana)" -msgstr "" +msgstr "[mana-file] : O arquivo mana é um arquivo XML (.mana)" #: ../src/gui/setup_interface.cpp:96 msgid "as particle" @@ -4024,7 +3838,7 @@ msgstr "baixo" #: ../src/main.cpp:49 msgid "mana [options] [mana-file]" -msgstr "" +msgstr "mana [opções] [arquivo-mana]" #: ../src/gui/setup_video.cpp:210 msgid "max" @@ -4040,12 +3854,12 @@ msgstr "desligado" #: ../src/gui/serverdialog.cpp:480 msgid "requires a newer version" -msgstr "" +msgstr "requer uma versão mais recente" #: ../src/gui/serverdialog.cpp:482 #, c-format msgid "requires v%s" -msgstr "" +msgstr "requer v%s" #: ../src/resources/beinginfo.cpp:34 ../src/resources/itemdb.cpp:241 #: ../src/resources/monsterdb.cpp:74 diff --git a/po/pt_BR.po b/po/pt_BR.po index cbab8262..51b66ac9 100644 --- a/po/pt_BR.po +++ b/po/pt_BR.po @@ -8,8 +8,8 @@ msgstr "" "Project-Id-Version: mana\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2024-10-23 09:58+0200\n" -"PO-Revision-Date: 2024-10-22 11:12+0000\n" -"Last-Translator: Allan Nordhøy <epost@anotheragency.no>\n" +"PO-Revision-Date: 2024-10-29 01:00+0000\n" +"Last-Translator: Antônio Neto <alasmirt@gmail.com>\n" "Language-Team: Portuguese (Brazil) <https://hosted.weblate.org/projects/mana/" "mana/pt_BR/>\n" "Language: pt_BR\n" @@ -17,7 +17,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" -"X-Generator: Weblate 5.8-rc\n" +"X-Generator: Weblate 5.8.2-dev\n" "X-Launchpad-Export-Date: 2010-03-05 19:28+0000\n" #: ../src/main.cpp:52 @@ -97,9 +97,8 @@ msgid " -v --version : Display the version" msgstr " -v --version : Exibe a versão" #: ../src/main.cpp:63 -#, fuzzy msgid " -y --server-type : Login server type" -msgstr " -s --server : Nome ou IP do servidor de login" +msgstr " -y --server-type : Tipo de servidor de login" #: ../src/gui/updaterwindow.cpp:410 msgid "##1 It is strongly recommended that" @@ -141,7 +140,7 @@ msgstr "%d FPS (OpenGL)" #: ../src/gui/setup_video.cpp:178 #, c-format msgid "%dx" -msgstr "" +msgstr "%dx" #: ../src/client.cpp:1074 ../src/client.cpp:1097 #, c-format @@ -191,7 +190,7 @@ msgstr "%s já é membro de um grupo." #: ../src/net/manaserv/partyhandler.cpp:160 #, c-format msgid "%s is already in a party." -msgstr "%s já é membro de um grupo." +msgstr "%s já está em um grupo." #: ../src/net/tmwa/partyhandler.cpp:356 #, c-format @@ -204,14 +203,14 @@ msgid "%s is now a member of your party." msgstr "%s agora é um membro do seu grupo." #: ../src/net/manaserv/partyhandler.cpp:129 -#, fuzzy, c-format +#, c-format msgid "%s joined the party on invitation from %s." -msgstr "Rejeitou convite para o grupo de %s." +msgstr "%s entrou no grupo a convite de %s." #: ../src/net/manaserv/partyhandler.cpp:127 -#, fuzzy, c-format +#, c-format msgid "%s joined the party." -msgstr "%s entrou no grupo%s." +msgstr "%s entrou no grupo." #: ../src/net/manaserv/chathandler.cpp:319 #, c-format @@ -319,12 +318,10 @@ msgid "/kick > Kick a user from the channel" msgstr "/kick > Expulsa um usuário do canal" #: ../src/net/tmwa/gui/guildtab.cpp:56 -#, fuzzy msgid "/kick > Kick someone from the guild you are in" msgstr "/kick > Expulsa alguém da guilda em que você está" #: ../src/net/tmwa/gui/partytab.cpp:55 -#, fuzzy msgid "/kick > Kick someone from the party you are in" msgstr "/kick > Expulsa alguém do grupo em que você está" @@ -465,7 +462,7 @@ msgstr "Convite para a guilda aceito" #: ../src/gui/socialwindow.cpp:485 #, c-format msgid "Accepted party invite from %s." -msgstr "Aceitou convite para o grupo de %s." +msgstr "Aceitou convite para o grupo de %s." #: ../src/game.cpp:713 msgid "Accepting incoming trade requests" @@ -607,16 +604,16 @@ msgid "Applying change to OpenGL requires restart." msgstr "Aplicando mudança a OpenGL requer reiniciar o jogo." #: ../src/gui/setup_video.cpp:386 -#, fuzzy msgid "" "Applying change to OpenGL requires restart.\n" "\n" "In case OpenGL messes up your game graphics, restart the game with the " "command line option \"--no-opengl\"." msgstr "" -"Mudanças no OpenGL requerem o reinício do cliente. Caso o OpenGL atrapalhe o " -"seu gráfico, abra o jogo através da linha de comando com a seguinte opção: " -"\"--no-opengl\"." +"Mudanças no OpenGL requerem o reinício do cliente.\n" +"\n" +"Caso o OpenGL atrapalhe o seu gráfico, abra o jogo através da linha de " +"comando com a seguinte opção: \"--no-opengl\"." #: ../src/gui/charselectdialog.cpp:66 msgid "Are you sure you want to delete this character?" @@ -641,9 +638,9 @@ msgid "Assign" msgstr "Atribuir" #: ../src/net/manaserv/charhandler.cpp:166 -#, fuzzy, c-format +#, c-format msgid "At least one stat is out of the permitted range: (%u - %u)." -msgstr "Pelo menos um status fora do limite permitido: (%u - %u)." +msgstr "Pelo menos um atributo está fora da faixa permitida: (%u - %u)." #: ../src/keyboardconfig.cpp:46 ../src/net/tmwa/generalhandler.cpp:236 msgid "Attack" @@ -674,7 +671,7 @@ msgstr "Falha de autenticação." #: ../src/gui/setup_video.cpp:176 #, c-format msgid "Auto (%dx)" -msgstr "" +msgstr "Auto (%dx)" #: ../src/localplayer.cpp:1023 msgid "Away" @@ -690,9 +687,8 @@ msgid "Being" msgstr "Personagem" #: ../src/gui/debugwindow.cpp:141 -#, fuzzy msgid "Being Ids" -msgstr "Personagem" +msgstr "Ids de Personagem" #: ../src/gui/debugwindow.cpp:137 msgid "Being collision radius" @@ -753,11 +749,10 @@ msgid "" "Cannot create a whisper tab for nick \"%s\"! It either already exists, or is " "you." msgstr "" -"Não é possível criar uma aba de mensagem privada para o nick \"%s\"! Ou ela " +"Não é possível criar uma aba de mensagem privada para o nick \"%s\"! Ou ela " "já existe ou é você mesmo." #: ../src/gui/socialwindow.cpp:662 -#, fuzzy msgid "Cannot create party. You are already in a party." msgstr "Não foi possível criar o grupo. Você já faz parte de um." @@ -1119,7 +1114,7 @@ msgstr "Conectando…" #: ../src/net/tmwa/network.cpp:540 msgid "Connection to server terminated. " -msgstr "Conexão com o servidor interrompida." +msgstr "Conexão com o servidor interrompida. " #: ../src/keyboardconfig.cpp:85 msgid "Copy Outfit" @@ -1147,9 +1142,8 @@ msgid "Could not steal anything..." msgstr "Não foi possível roubar nada..." #: ../src/game.cpp:290 -#, fuzzy msgid "Could not take screenshot!" -msgstr "Não foi possível criar o grupo." +msgstr "Não foi possível criar a screenshot!" #: ../src/gui/charcreatedialog.cpp:85 ../src/gui/charselectdialog.cpp:393 #: ../src/gui/socialwindow.cpp:365 @@ -1196,9 +1190,8 @@ msgid "Cursor: (%d, %d)" msgstr "Cursor: (%d, %d)" #: ../src/gui/setup_video.cpp:102 -#, fuzzy msgid "Custom" -msgstr "Servidor customizado" +msgstr "Customizado" #: ../src/gui/customserverdialog.cpp:50 msgid "Custom Server" @@ -1471,21 +1464,17 @@ msgid "Failed adding item. Trade partner is over weighted." msgstr "Erro ao adicionar item. Parceiro de negócios carregando muito peso." #: ../src/net/tmwa/tradehandler.cpp:214 -#, fuzzy msgid "Failed adding item. You can't trade this item." -msgstr "" -"Falha ao adicionar item. Você não pode duplicar este tipo de item na janela." +msgstr "Falha ao adicionar item. Você não pode negociar este item." #: ../src/gui/tradewindow.cpp:262 -#, fuzzy msgid "Failed adding item. You cannot overlap one kind of item on the window." msgstr "" "Falha ao adicionar item. Você não pode duplicar este tipo de item na janela." #: ../src/gui/setup_video.cpp:374 -#, fuzzy msgid "Failed to change video mode." -msgstr "Falha ao usar item." +msgstr "Falha ao alterar o modo de vídeo." #: ../src/net/tmwa/charserverhandler.cpp:136 msgid "Failed to create character. Most likely the name is already taken." @@ -1540,7 +1529,6 @@ msgid "Friend" msgstr "Amigo" #: ../src/gui/setup_video.cpp:221 -#, fuzzy msgid "Fullscreen" msgstr "Tela cheia" @@ -1550,12 +1538,11 @@ msgstr "Nomes dos GMs" #: ../src/gui/debugwindow.cpp:142 msgid "GUI debug" -msgstr "" +msgstr "Depuração da interface gráfica" #: ../src/gui/setup_interface.cpp:112 -#, fuzzy msgid "GUI opacity" -msgstr "Opacidade" +msgstr "Opacidade da interface gráfica" #: ../src/net/tmwa/gamehandler.cpp:89 msgid "Game" @@ -1613,9 +1600,8 @@ msgid "Guild created." msgstr "Guilda criada." #: ../src/net/tmwa/guildhandler.cpp:63 -#, fuzzy msgid "Guild creation isn't supported." -msgstr "A criação de guildas ainda não é suportada." +msgstr "A criação de guildas não é suportada." #: ../src/net/tmwa/gui/guildtab.cpp:81 msgid "Guild name is missing." @@ -1776,6 +1762,7 @@ msgstr "Nome inválido." #: ../src/main.cpp:173 msgid "Invalid server type, expected one of: tmwathena, manaserv" msgstr "" +"Tipo de servidor inválido, esperado um dos seguintes: tmwathena, manaserv" #: ../src/net/manaserv/charhandler.cpp:172 msgid "Invalid slot number." @@ -1813,23 +1800,20 @@ msgid "Invite %s to join your party" msgstr "Convidar %s para o seu grupo" #: ../src/net/manaserv/guildhandler.cpp:108 -#, fuzzy msgid "Invite failed." -msgstr "Falha ao sentar!" +msgstr "Convite falhou." #: ../src/net/manaserv/guildhandler.cpp:96 msgid "Invite sent." msgstr "Convite enviado." #: ../src/net/manaserv/guildhandler.cpp:104 -#, fuzzy msgid "Invited player can't join another guild." -msgstr "Convidar %s para a sua guilda" +msgstr "O jogador convidado não pode se juntar a outra guilda." #: ../src/net/manaserv/guildhandler.cpp:100 -#, fuzzy msgid "Invited player is already in that guild." -msgstr "Convidou o jogador %s para a guilda %s." +msgstr "O jogador convidado já está nessa guilda." #: ../src/gui/socialwindow.cpp:116 #, c-format @@ -1867,7 +1851,7 @@ msgstr "Este item pertence a outra pessoa." #: ../src/localplayer.cpp:866 msgid "Item is too far away" -msgstr "Este item está muito longe." +msgstr "Este item está muito longe" #: ../src/localplayer.cpp:865 msgid "Item is too heavy." @@ -2063,7 +2047,7 @@ msgstr "Média" #: ../src/gui/socialwindow.cpp:143 msgid "Member Invite to Guild" -msgstr "Convite de membros para a Guilda." +msgstr "Convite de membros para a Guilda" #: ../src/gui/socialwindow.cpp:214 msgid "Member Invite to Party" @@ -2221,7 +2205,7 @@ msgstr "<nick> não foi informado." #: ../src/net/manaserv/charhandler.cpp:142 msgid "No empty slot." -msgstr "Sem espaço" +msgstr "Sem espaço vazio." #: ../src/net/manaserv/charhandler.cpp:265 msgid "No gameservers are available." @@ -2275,9 +2259,8 @@ msgid "Notice" msgstr "Anúncio" #: ../src/gui/setup_audio.cpp:51 -#, fuzzy msgid "Notifications volume" -msgstr "Aviso de experiência" +msgstr "Notificações de volume" #: ../src/gui/itemamountwindow.cpp:112 ../src/gui/okdialog.cpp:40 #: ../src/gui/quitdialog.cpp:46 ../src/gui/textdialog.cpp:39 @@ -2300,25 +2283,24 @@ msgstr "Senha antiga incorreta." #: ../src/gui/socialwindow.cpp:380 ../src/gui/socialwindow.cpp:676 #, c-format msgid "Online (%zu)" -msgstr "" +msgstr "Online (%zu)" #: ../src/gui/widgets/itemlinkhandler.cpp:66 #: ../src/gui/widgets/itemlinkhandler.cpp:95 msgid "Open URL Failed" -msgstr "" +msgstr "Falha ao abrir a URL" #: ../src/gui/widgets/itemlinkhandler.cpp:63 -#, fuzzy msgid "Open URL?" -msgstr "OpenGL" +msgstr "Abrir URL?" #: ../src/gui/setup_video.cpp:228 msgid "OpenGL (Legacy)" -msgstr "" +msgstr "OpenGL (Legado)" #: ../src/gui/widgets/itemlinkhandler.cpp:67 msgid "Opening of URLs requires SDL 2.0.14." -msgstr "" +msgstr "A abertura de URLs requer SDL 2.0.14." #: ../src/commandhandler.h:31 #, c-format @@ -2462,9 +2444,9 @@ msgid "Play" msgstr "Jogar" #: ../src/net/manaserv/guildhandler.cpp:259 -#, fuzzy, c-format +#, c-format msgid "Player %s kicked you out of guild %s." -msgstr "%s te convidou para entrar na guilda %s." +msgstr "O jogador %s te expulsou da guilda %s." #: ../src/commandhandler.cpp:521 msgid "Player already ignored!" @@ -2518,9 +2500,8 @@ msgid "Please select a custom server." msgstr "Por favor, selecione um servidor customizado." #: ../src/gui/serverdialog.cpp:272 -#, fuzzy msgid "Please select a valid server." -msgstr "Por favor, selecione um servidor." +msgstr "Por favor, selecione um servidor válido." #: ../src/commandhandler.cpp:436 ../src/commandhandler.cpp:515 #: ../src/commandhandler.cpp:537 @@ -2528,9 +2509,8 @@ msgid "Please specify a name." msgstr "Por favor, especifique um nome." #: ../src/gui/customserverdialog.cpp:167 -#, fuzzy msgid "Please type in at least the address of the server." -msgstr "Por favor especifique pelo menos o endereço e a porta do servidor." +msgstr "Por favor, digite pelo menos o endereço do servidor." #: ../src/net/tmwa/specialhandler.cpp:212 msgid "Poison had no effect..." @@ -2619,7 +2599,7 @@ msgstr "Registrar" #: ../src/gui/logindialog.cpp:119 msgid "Registration disabled" -msgstr "Registro desabilitado." +msgstr "Registro desabilitado" #: ../src/net/tmwa/loginhandler.cpp:169 msgid "Rejected from server." @@ -2632,7 +2612,7 @@ msgstr "Convite para guilda rejeitado." #: ../src/gui/socialwindow.cpp:491 #, c-format msgid "Rejected party invite from %s." -msgstr "Rejeitou convite para o grupo de %s." +msgstr "Rejeitou convite para o grupo de %s." #: ../src/gui/setup_players.cpp:56 msgid "Relation" @@ -2673,9 +2653,8 @@ msgid "Reset Windows" msgstr "Restaurar janelas" #: ../src/gui/setup_video.cpp:313 -#, fuzzy msgid "Resolution:" -msgstr "Relação" +msgstr "Resolução:" #: ../src/gui/inventorywindow.cpp:132 ../src/gui/popupmenu.cpp:389 msgid "Retrieve" @@ -2702,9 +2681,8 @@ msgid "Rotate the stick" msgstr "Gire o bastão" #: ../src/gui/setup_audio.cpp:50 -#, fuzzy msgid "SFX volume" -msgstr "Volume Sfx" +msgstr "Volume dos efeitos sonoros" #: ../src/net/manaserv/beinghandler.cpp:290 #: ../src/net/tmwa/playerhandler.cpp:109 @@ -2717,16 +2695,16 @@ msgstr "Falha ao salvar screenshot!" #: ../src/gui/setup_video.cpp:315 msgid "Scale:" -msgstr "" +msgstr "Escala:" #: ../src/keyboardconfig.cpp:57 msgid "Screenshot" msgstr "Screenshot" #: ../src/game.cpp:328 -#, fuzzy, c-format +#, c-format msgid "Screenshot saved as %s" -msgstr "Screenshot salva como " +msgstr "Screenshot salva como %s" #: ../src/keyboardconfig.cpp:100 msgid "Scroll Chat Down" @@ -3082,7 +3060,7 @@ msgstr "As novas senhas não são iguais." #: ../src/gui/changepassworddialog.cpp:116 #, c-format msgid "The new password needs to be at least %d characters long." -msgstr "A nova senha deve ter pelo menos %d caracteres." +msgstr "A nova senha deve ter pelo menos %d caracteres." #: ../src/gui/changepassworddialog.cpp:123 #, c-format @@ -3139,7 +3117,7 @@ msgstr "Este comando limpa a janela de chat." #: ../src/gui/widgets/whispertab.cpp:84 msgid "This command closes the current whisper tab." -msgstr "Este comando fecha a atual aba de mensagem privada" +msgstr "Este comando fecha a atual aba de mensagem privada." #: ../src/commandhandler.cpp:260 msgid "This command creates a new party called <name>." @@ -3151,7 +3129,7 @@ msgstr "Exibe uma lista de todos os comandos disponíveis." #: ../src/commandhandler.cpp:200 msgid "This command displays help on <command>." -msgstr "Exibe o conteúdo de ajuda de <comando>" +msgstr "Exibe o conteúdo de ajuda de <comando>." #: ../src/commandhandler.cpp:304 msgid "This command displays the name of the current map." @@ -3272,7 +3250,6 @@ msgstr "" "Este comando mostra que você está longe do teclado, indicando a razão dada." #: ../src/commandhandler.cpp:246 -#, fuzzy msgid "This command tries to make a tab for whispers between you and <nick>." msgstr "Este comando cria uma aba para mensagens privadas entre você e <nick>." @@ -3367,7 +3344,7 @@ msgstr "Transparência desabilitada" #: ../src/gui/setup_video.cpp:410 msgid "Transparency enabled" -msgstr "Transparência habilitada." +msgstr "Transparência habilitada" #: ../src/localplayer.cpp:864 msgid "Tried to pick up nonexistent item." @@ -3398,9 +3375,9 @@ msgid "Unable to equip." msgstr "Impossível equipar." #: ../src/net/tmwa/network.cpp:470 -#, fuzzy, c-format +#, c-format msgid "Unable to resolve host \"%s\"" -msgstr "Não foi possível determinar o host \"" +msgstr "Não foi possível determinar o host \"%s\"" #: ../src/net/tmwa/buysellhandler.cpp:124 msgid "Unable to sell." @@ -3500,7 +3477,7 @@ msgstr "ID não registrado." #: ../src/gui/skilldialog.cpp:220 msgid "Up" -msgstr "+" +msgstr "Acima" #: ../src/gui/updaterwindow.cpp:123 msgid "Updating..." @@ -3520,7 +3497,7 @@ msgstr "Usuário excluído permamentemente." #: ../src/gui/setup_video.cpp:227 msgid "VSync" -msgstr "" +msgstr "VSync" #: ../src/gui/setup_video.cpp:244 msgid "Video" @@ -3622,19 +3599,16 @@ msgid "Willpower %+.1f" msgstr "Força de vontade %+.1f" #: ../src/gui/setup_video.cpp:311 -#, fuzzy msgid "Window mode:" -msgstr " modo de video: " +msgstr "Modo de video:" #: ../src/gui/setup_video.cpp:221 -#, fuzzy msgid "Windowed" -msgstr "em janela" +msgstr "Modo janela" #: ../src/gui/setup_video.cpp:221 -#, fuzzy msgid "Windowed Fullscreen" -msgstr "Tela cheia" +msgstr "Modo janela em tela cheia" #: ../src/net/manaserv/loginhandler.cpp:92 msgid "Wrong magic_token." @@ -3662,7 +3636,7 @@ msgstr "Você morreu" #: ../src/net/tmwa/playerhandler.cpp:130 msgid "You are an ex-player." -msgstr "Você é um ex-jogador" +msgstr "Você é um ex-jogador." #: ../src/net/tmwa/playerhandler.cpp:254 msgid "" @@ -3686,7 +3660,6 @@ msgid "You are not that alive anymore." msgstr "Você não me parece assim tão vivo." #: ../src/net/tmwa/partyhandler.cpp:328 -#, fuzzy msgid "You can only invite when you are in a party!" msgstr "Você só pode fazer convites se estiver em um grupo!" @@ -3827,7 +3800,7 @@ msgstr "Você chutou o balde." #: ../src/net/tmwa/playerhandler.cpp:128 msgid "" "You've shuffled off your mortal coil, run down the curtain and joined the " -"bleedin' choir invisibile." +"bleedin' choir invisible." msgstr "" "Você dispensou seu corpo mortal, abaixou as cortinas e juntou-se ao maldito " "coro invisível." @@ -3870,7 +3843,7 @@ msgstr "baixo" #: ../src/main.cpp:49 msgid "mana [options] [mana-file]" -msgstr "mana [opções] [arquivo-mana]" +msgstr "mana [opções] [arquivo-mana]" #: ../src/gui/setup_video.cpp:210 msgid "max" @@ -3821,7 +3821,7 @@ msgstr "Вы приказали долго жить." #: ../src/net/tmwa/playerhandler.cpp:128 msgid "" "You've shuffled off your mortal coil, run down the curtain and joined the " -"bleedin' choir invisibile." +"bleedin' choir invisible." msgstr "" "Вы осознали суть экзистенции, не выдержали тленности бытия, её " "несправедливости и иррациональности и в порыве безысходности решили привести " @@ -3799,7 +3799,7 @@ msgstr "" #: ../src/net/tmwa/playerhandler.cpp:128 msgid "" "You've shuffled off your mortal coil, run down the curtain and joined the " -"bleedin' choir invisibile." +"bleedin' choir invisible." msgstr "" #: ../src/net/tmwa/playerhandler.cpp:125 @@ -3741,7 +3741,7 @@ msgstr "" #: ../src/net/tmwa/playerhandler.cpp:128 msgid "" "You've shuffled off your mortal coil, run down the curtain and joined the " -"bleedin' choir invisibile." +"bleedin' choir invisible." msgstr "" #: ../src/net/tmwa/playerhandler.cpp:125 @@ -3988,7 +3988,7 @@ msgstr "Du har kastat in handduken." #: ../src/net/tmwa/playerhandler.cpp:128 msgid "" "You've shuffled off your mortal coil, run down the curtain and joined the " -"bleedin' choir invisibile." +"bleedin' choir invisible." msgstr "Du tog ner skylten, kilade runt hörnet och bet i gräset." #: ../src/net/tmwa/playerhandler.cpp:125 diff --git a/po/ta.po b/po/ta.po new file mode 100644 index 00000000..ebb022af --- /dev/null +++ b/po/ta.po @@ -0,0 +1,3882 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-10-23 09:58+0200\n" +"PO-Revision-Date: 2025-06-24 16:01+0000\n" +"Last-Translator: தமிழ்நேரம் <anishprabu.t@gmail.com>\n" +"Language-Team: Tamil <https://hosted.weblate.org/projects/mana/mana/ta/>\n" +"Language: ta\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 5.13-dev\n" + +#: ../src/client.cpp:529 ../src/gui/setup.cpp:46 ../src/gui/windowmenu.cpp:71 +msgid "Setup" +msgstr "அமைவு" + +#: ../src/client.cpp:605 +msgid "Connecting to server" +msgstr "சேவையகத்துடன் இணைக்கிறது" + +#: ../src/client.cpp:631 +msgid "Logging in" +msgstr "உள்நுழைவு -.காம்" + +#: ../src/client.cpp:659 +msgid "Entering game world" +msgstr "விளையாட்டு உலகில் நுழைகிறது" + +#: ../src/client.cpp:733 +msgid "Requesting characters" +msgstr "எழுத்துக்களைக் கோருகிறது" + +#: ../src/client.cpp:766 +msgid "Connecting to the game server" +msgstr "விளையாட்டு சேவையகத்துடன் இணைக்கிறது" + +#: ../src/client.cpp:776 +msgid "Changing game servers" +msgstr "விளையாட்டு சேவையகங்களை மாற்றுதல்" + +#: ../src/client.cpp:817 +msgid "Requesting registration details" +msgstr "பதிவு விவரங்களை கோருகிறது" + +#: ../src/client.cpp:845 +msgid "Password Change" +msgstr "கடவுச்சொல் மாற்றம்" + +#: ../src/client.cpp:846 +msgid "Password changed successfully!" +msgstr "கடவுச்சொல் வெற்றிகரமாக மாற்றப்பட்டது!" + +#: ../src/client.cpp:864 +msgid "Email Change" +msgstr "மின்னஞ்சல் மாற்றம்" + +#: ../src/client.cpp:865 +msgid "Email changed successfully!" +msgstr "மின்னஞ்சல் வெற்றிகரமாக மாற்றப்பட்டது!" + +#: ../src/client.cpp:884 +msgid "Unregister Successful" +msgstr "பதிவுசெய்தல் வெற்றிகரமாக" + +#: ../src/client.cpp:885 +msgid "Farewell, come back any time..." +msgstr "விடைபெறுங்கள், எந்த நேரத்திலும் திரும்பி வாருங்கள் ..." + +#: ../src/client.cpp:966 ../src/gui/changeemaildialog.cpp:156 +#: ../src/gui/changepassworddialog.cpp:149 ../src/gui/charcreatedialog.cpp:198 +#: ../src/gui/customserverdialog.cpp:166 ../src/gui/register.cpp:218 +#: ../src/gui/serverdialog.cpp:271 ../src/gui/serverdialog.cpp:315 +#: ../src/gui/setup_video.cpp:374 ../src/gui/unregisterdialog.cpp:130 +#: ../src/net/manaserv/charhandler.cpp:178 +#: ../src/net/manaserv/charhandler.cpp:228 +#: ../src/net/tmwa/charserverhandler.cpp:136 +#: ../src/net/tmwa/charserverhandler.cpp:153 +msgid "Error" +msgstr "பிழை" + +#: ../src/client.cpp:1074 ../src/client.cpp:1097 +#, c-format +msgid "%s doesn't exist and can't be created! Exiting." +msgstr "%s இல்லை, உருவாக்க முடியாது! வெளியேறுதல்." + +#: ../src/client.cpp:1171 +#, c-format +msgid "Invalid update host: %s" +msgstr "தவறான புதுப்பிப்பு ஓச்ட்: %s" + +#: ../src/client.cpp:1203 +#, c-format +msgid "" +"Error creating updates directory!\n" +"(%s)" +msgstr "" +"புதுப்பிப்புகள் கோப்பகத்தை உருவாக்குவது பிழை!\n" +" (%s)" + +#: ../src/client.cpp:1211 +#, c-format +msgid "" +"Error creating updates directory!\n" +"(%s/%s)" +msgstr "" +"புதுப்பிப்புகள் கோப்பகத்தை உருவாக்குவது பிழை!\n" +" (%s/%s)" + +#: ../src/commandhandler.cpp:128 ../src/commandhandler.cpp:314 +msgid "Unknown command." +msgstr "தெரியாத கட்டளை." + +#: ../src/commandhandler.cpp:152 +msgid "-- Help --" +msgstr "-உதவி-" + +#: ../src/commandhandler.cpp:153 +msgid "/help > Display this help" +msgstr "/உதவி> இந்த உதவியைக் காண்பி" + +#: ../src/commandhandler.cpp:155 +msgid "/where > Display map name" +msgstr "/எங்கே> வரைபடப் பெயரைக் காண்பி" + +#: ../src/commandhandler.cpp:158 +msgid "/who > Display number of online users" +msgstr "/யார்> நிகழ்நிலை பயனர்களின் எண்ணிக்கையைக் காண்பி" + +#: ../src/commandhandler.cpp:160 +msgid "/me > Tell something about yourself" +msgstr "/me> உங்களைப் பற்றி ஏதாவது சொல்லுங்கள்" + +#: ../src/commandhandler.cpp:162 +msgid "/clear > Clears this window" +msgstr "/அழி> இந்த சாளரத்தை அழிக்கிறது" + +#: ../src/commandhandler.cpp:164 +msgid "/msg > Send a private message to a user" +msgstr "/msg> ஒரு பயனருக்கு ஒரு தனிப்பட்ட செய்தியை அனுப்பவும்" + +#: ../src/commandhandler.cpp:165 +msgid "/whisper > Alias of msg" +msgstr "/விச்பர்> எம்.எச்.சி." + +#: ../src/commandhandler.cpp:166 +msgid "/w > Alias of msg" +msgstr "/w> MSG இன் மாற்றுப்பெயர்" + +#: ../src/commandhandler.cpp:167 +msgid "/query > Makes a tab for private messages with another user" +msgstr "" +"/வினவல்> மற்றொரு பயனருடன் தனிப்பட்ட செய்திகளுக்கு ஒரு தாவலை உருவாக்குகிறது" + +#: ../src/commandhandler.cpp:169 +msgid "/q > Alias of query" +msgstr "/q> வினவலின் மாற்றுப்பெயர்" + +#: ../src/commandhandler.cpp:171 +msgid "/away > Tell the other whispering players you're away from keyboard." +msgstr "" +"/விலகி> விசைப்பலகையிலிருந்து நீங்கள் விலகி இருக்கும் மற்ற கிசுகிசுக்கும் வீரர்களிடம் " +"சொல்லுங்கள்." + +#: ../src/commandhandler.cpp:174 +msgid "/ignore > ignore a player" +msgstr "/புறக்கணிக்கவும்> ஒரு வீரரை புறக்கணிக்கவும்" + +#: ../src/commandhandler.cpp:175 +msgid "/unignore > stop ignoring a player" +msgstr "/unignore> ஒரு வீரரை புறக்கணிப்பதை நிறுத்துங்கள்" + +#: ../src/commandhandler.cpp:177 +msgid "/list > Display all public channels" +msgstr "/பட்டியல்> அனைத்து பொது சேனல்களையும் காண்பி" + +#: ../src/commandhandler.cpp:178 +msgid "/join > Join or create a channel" +msgstr "/சேர> சேனலில் சேரவும் அல்லது உருவாக்கவும்" + +#: ../src/commandhandler.cpp:180 +msgid "/createparty > Create a new party" +msgstr "/கிரியேட்ட்பார்டி> ஒரு புதிய விருந்தை உருவாக்குங்கள்" + +#: ../src/commandhandler.cpp:181 +msgid "/party > Invite a user to party" +msgstr "/கட்சி> ஒரு பயனரை விருந்துக்கு அழைக்கவும்" + +#: ../src/commandhandler.cpp:183 +msgid "/record > Start recording the chat to an external file" +msgstr "/பதிவு> அரட்டையை வெளிப்புற கோப்பில் பதிவு செய்யத் தொடங்குங்கள்" + +#: ../src/commandhandler.cpp:185 +msgid "/toggle > Determine whether <return> toggles the chat log" +msgstr "/மாற்று> <ரிட்டர்ன்> அரட்டை பதிவை மாற்றுகிறதா என்பதை தீர்மானிக்கவும்" + +#: ../src/commandhandler.cpp:187 +msgid "/present > Get list of players present (sent to chat log, if logging)" +msgstr "" +"/தற்போதைய> தற்போதுள்ள வீரர்களின் பட்டியலைப் பெறுங்கள் (அரட்டை பதிவுக்கு அனுப்பப்பட்டது, " +"உள்நுழைந்தால்)" + +#: ../src/commandhandler.cpp:192 +msgid "For more information, type /help <command>." +msgstr "மேலும் தகவலுக்கு, தட்டச்சு /உதவி <கட்டளை>." + +#: ../src/commandhandler.cpp:196 +msgid "Command: /help" +msgstr "கட்டளை: /உதவி" + +#: ../src/commandhandler.cpp:197 +msgid "This command displays a list of all commands available." +msgstr "" +"இந்த கட்டளை கிடைக்கக்கூடிய அனைத்து கட்டளைகளின் பட்டியலையும் காட்டுகிறது." + +#: ../src/commandhandler.cpp:199 +msgid "Command: /help <command>" +msgstr "கட்டளை: /உதவி <கட்டளை>" + +#: ../src/commandhandler.cpp:200 +msgid "This command displays help on <command>." +msgstr "இந்த கட்டளை <கட்டளை> இல் உதவியைக் காட்டுகிறது." + +#: ../src/commandhandler.cpp:208 +msgid "Command: /clear" +msgstr "கட்டளை: /அழி" + +#: ../src/commandhandler.cpp:209 +msgid "This command clears the chat log of previous chat." +msgstr "இந்த கட்டளை முந்தைய அரட்டையின் அரட்டை பதிவை அழிக்கிறது." + +#: ../src/commandhandler.cpp:213 +msgid "Command: /ignore <player>" +msgstr "கட்டளை: /புறக்கணிக்கவும் <boater>" + +#: ../src/commandhandler.cpp:214 +msgid "This command ignores the given player regardless of current relations." +msgstr "" +"தற்போதைய உறவுகளைப் பொருட்படுத்தாமல் இந்த கட்டளை கொடுக்கப்பட்ட வீரரை புறக்கணிக்கிறது." + +#: ../src/commandhandler.cpp:219 +msgid "Command: /join <channel>" +msgstr "கட்டளை: /சேர <சேனல்>" + +#: ../src/commandhandler.cpp:220 +msgid "This command makes you enter <channel>." +msgstr "இந்த கட்டளை உங்களை <சேனல்> உள்ளிட வைக்கிறது." + +#: ../src/commandhandler.cpp:221 +msgid "If <channel> doesn't exist, it's created." +msgstr "<anunalor> இல்லை என்றால், அது உருவாக்கப்பட்டது." + +#: ../src/commandhandler.cpp:225 +msgid "Command: /list" +msgstr "கட்டளை: /பட்டியல்" + +#: ../src/commandhandler.cpp:226 +msgid "This command shows a list of all channels." +msgstr "இந்த கட்டளை அனைத்து சேனல்களின் பட்டியலையும் காட்டுகிறது." + +#: ../src/commandhandler.cpp:230 +msgid "Command: /me <message>" +msgstr "கட்டளை: /நான் <செய்தி>" + +#: ../src/commandhandler.cpp:231 +msgid "This command tell others you are (doing) <msg>." +msgstr "" +"இந்த கட்டளை நீங்கள் (செய்கிறீர்கள்) <msg> என்று மற்றவர்களிடம் கூறுகிறது." + +#: ../src/commandhandler.cpp:235 +msgid "Command: /msg <nick> <message>" +msgstr "கட்டளை: /msg <நிக்> <செய்தி>" + +#: ../src/commandhandler.cpp:236 +msgid "Command: /whisper <nick> <message>" +msgstr "கட்டளை: /விச்பர் <நிக்> <செய்தி>" + +#: ../src/commandhandler.cpp:237 +msgid "Command: /w <nick> <message>" +msgstr "கட்டளை: /w <நிக்> <செய்தி>" + +#: ../src/commandhandler.cpp:238 +msgid "This command sends the text <message> to <nick>." +msgstr "இந்த கட்டளை <நிக்> என்ற உரையை <நிக்> க்கு அனுப்புகிறது." + +#: ../src/commandhandler.cpp:239 ../src/commandhandler.cpp:266 +#: ../src/gui/widgets/channeltab.cpp:81 ../src/gui/widgets/channeltab.cpp:90 +#: ../src/net/tmwa/gui/guildtab.cpp:67 ../src/net/tmwa/gui/partytab.cpp:68 +msgid "If the <nick> has spaces in it, enclose it in double quotes (\")." +msgstr "" +"<நிக்> அதில் இடங்களைக் கொண்டிருந்தால், அதை இரட்டை மேற்கோள்களில் (\") இணைக்கவும்." + +#: ../src/commandhandler.cpp:244 +msgid "Command: /query <nick>" +msgstr "கட்டளை: /வினவல் <நிக்>" + +#: ../src/commandhandler.cpp:245 +msgid "Command: /q <nick>" +msgstr "கட்டளை: /q <நிக்>" + +#: ../src/commandhandler.cpp:246 +msgid "This command tries to make a tab for whispers between you and <nick>." +msgstr "" +"இந்த கட்டளை உங்களுக்கும் <நிக்> க்கும் இடையிலான கிசுகிசுக்களுக்கு ஒரு தாவலை உருவாக்க " +"முயற்சிக்கிறது." + +#: ../src/commandhandler.cpp:251 +msgid "Command: /away <afk reason>" +msgstr "கட்டளை: /தொலைவில் <afk காரணம்>" + +#: ../src/commandhandler.cpp:252 +msgid "This command tells you're away from keyboard with the given reason." +msgstr "" +"கொடுக்கப்பட்ட காரணத்துடன் நீங்கள் விசைப்பலகையிலிருந்து விலகி இருக்கிறீர்கள் என்று இந்த கட்டளை " +"கூறுகிறது." + +#: ../src/commandhandler.cpp:254 +msgid "Command: /away" +msgstr "கட்டளை: /தொலைவில்" + +#: ../src/commandhandler.cpp:255 +msgid "This command clears the away status and message." +msgstr "இந்த கட்டளை தொலைதூர நிலை மற்றும் செய்தியை அழிக்கிறது." + +#: ../src/commandhandler.cpp:259 +msgid "Command: /createparty <name>" +msgstr "கட்டளை: /கிரியேட்டிவார்டி <பெயர்>" + +#: ../src/commandhandler.cpp:260 +msgid "This command creates a new party called <name>." +msgstr "இந்த கட்டளை <பெயர்> என்ற புதிய கட்சியை உருவாக்குகிறது." + +#: ../src/commandhandler.cpp:264 +msgid "Command: /party <nick>" +msgstr "கட்டளை: /கட்சி <நிக்>" + +#: ../src/commandhandler.cpp:265 ../src/net/tmwa/gui/partytab.cpp:67 +msgid "This command invites <nick> to party with you." +msgstr "இந்த கட்டளை உங்களுடன் விருந்துக்கு <நிக்> ஐ அழைக்கிறது." + +#: ../src/commandhandler.cpp:271 +msgid "Command: /present" +msgstr "கட்டளை: /தற்போது" + +#: ../src/commandhandler.cpp:272 +msgid "" +"This command gets a list of players within hearing and sends it to either " +"the record log if recording, or the chat log otherwise." +msgstr "" +"இந்த கட்டளை செவிமடுக்கும் வீரர்களின் பட்டியலைப் பெறுகிறது மற்றும் பதிவுசெய்தால் பதிவு " +"பதிவுக்கு அனுப்புகிறது, அல்லது அரட்டை பதிவு இல்லையெனில்." + +#: ../src/commandhandler.cpp:278 +msgid "Command: /record <filename>" +msgstr "கட்டளை: /பதிவு <கோப்பு பெயர்>" + +#: ../src/commandhandler.cpp:279 +msgid "This command starts recording the chat log to the file <filename>." +msgstr "" +"இந்த கட்டளை அரட்டை பதிவை <கோப்பு பெயர்> கோப்பில் பதிவு செய்யத் தொடங்குகிறது." + +#: ../src/commandhandler.cpp:281 +msgid "Command: /record" +msgstr "கட்டளை: /பதிவு" + +#: ../src/commandhandler.cpp:282 +msgid "This command finishes a recording session." +msgstr "இந்த கட்டளை ஒரு பதிவு அமர்வை முடிக்கிறது." + +#: ../src/commandhandler.cpp:286 +msgid "Command: /toggle <state>" +msgstr "கட்டளை: /மாற்று <state>" + +#: ../src/commandhandler.cpp:287 +msgid "" +"This command sets whether the return key should toggle the chat log, or " +"whether the chat log turns off automatically." +msgstr "" +"திரும்பும் விசை அரட்டை பதிவை மாற்ற வேண்டுமா, அல்லது அரட்டை பதிவு தானாகவே " +"அணைக்கப்படுகிறதா என்பதை இந்த கட்டளை அமைக்கிறது." + +#: ../src/commandhandler.cpp:289 +msgid "" +"<state> can be one of \"1\", \"yes\", \"true\" to turn the toggle on, or " +"\"0\", \"no\", \"false\" to turn the toggle off." +msgstr "" +"<state> மாற்றத்தை இயக்க \"1\", \"ஆம்\", \"உண்மை\" அல்லது \"0\", \"இல்லை\", \"தவறு\" " +"ஆகியவற்றில் ஒன்றாகும்." + +#: ../src/commandhandler.cpp:292 +msgid "Command: /toggle" +msgstr "கட்டளை: /மாற்று" + +#: ../src/commandhandler.cpp:293 +msgid "This command displays the return toggle status." +msgstr "இந்த கட்டளை திரும்பும் நிலை நிலையை காட்டுகிறது." + +#: ../src/commandhandler.cpp:297 ../src/gui/widgets/whispertab.cpp:94 +msgid "Command: /unignore <player>" +msgstr "கட்டளை: /Uniginore <ploater>" + +#: ../src/commandhandler.cpp:298 +msgid "This command stops ignoring the given player if they are being ignored" +msgstr "" +"கொடுக்கப்பட்ட வீரரை புறக்கணித்தால் புறக்கணிப்பதை இந்த கட்டளை நிறுத்துகிறது" + +#: ../src/commandhandler.cpp:303 +msgid "Command: /where" +msgstr "கட்டளை: /எங்கே" + +#: ../src/commandhandler.cpp:304 +msgid "This command displays the name of the current map." +msgstr "இந்த கட்டளை தற்போதைய வரைபடத்தின் பெயரைக் காட்டுகிறது." + +#: ../src/commandhandler.cpp:308 +msgid "Command: /who" +msgstr "கட்டளை: /யார்" + +#: ../src/commandhandler.cpp:309 +msgid "This command displays the number of players currently online." +msgstr "இந்த கட்டளை தற்போது ஆன்லைனில் வீரர்களின் எண்ணிக்கையைக் காட்டுகிறது." + +#: ../src/commandhandler.cpp:315 +msgid "Type /help for a list of commands." +msgstr "கட்டளைகளின் பட்டியலுக்கு தட்டச்சு /உதவி." + +#: ../src/commandhandler.cpp:381 +msgid "Cannot send empty whispers!" +msgstr "வெற்று கிசுகிசுக்களை அனுப்ப முடியாது!" + +#: ../src/commandhandler.cpp:388 +msgid "No <nick> was given." +msgstr "இல்லை <நிக்> வழங்கப்பட்டது." + +#: ../src/commandhandler.cpp:402 +#, c-format +msgid "" +"Cannot create a whisper tab for nick \"%s\"! It either already exists, or is " +"you." +msgstr "" +"நிக் \"%s\" க்கு ஒரு விச்பர் தாவலை உருவாக்க முடியாது! இது ஏற்கனவே உள்ளது, அல்லது நீங்கள்" +" தான்." + +#: ../src/commandhandler.cpp:416 +#, c-format +msgid "Requesting to join channel %s." +msgstr "சேனல் %s இல் சேரக் கோருகிறது." + +#: ../src/commandhandler.cpp:428 ../src/net/tmwa/gui/partytab.cpp:102 +msgid "Party name is missing." +msgstr "கட்சி பெயர் காணவில்லை." + +#: ../src/commandhandler.cpp:436 ../src/commandhandler.cpp:515 +#: ../src/commandhandler.cpp:537 +msgid "Please specify a name." +msgstr "தயவுசெய்து ஒரு பெயரைக் குறிப்பிடவும்." + +#: ../src/commandhandler.cpp:456 +msgid "Return toggles chat." +msgstr "அரட்டை மாற்றவும்." + +#: ../src/commandhandler.cpp:456 +msgid "Message closes chat." +msgstr "செய்தி அரட்டையை மூடுகிறது." + +#: ../src/commandhandler.cpp:465 +msgid "Return now toggles chat." +msgstr "இப்போது திரும்ப அரட்டை மாற்றுகிறது." + +#: ../src/commandhandler.cpp:469 +msgid "Message now closes chat." +msgstr "செய்தி இப்போது அரட்டையை மூடுகிறது." + +#: ../src/commandhandler.cpp:482 ../src/commandhandler.cpp:495 +msgid "Show IP: On" +msgstr "ஐபி: ஆன்" + +#: ../src/commandhandler.cpp:482 ../src/commandhandler.cpp:491 +msgid "Show IP: Off" +msgstr "ஐபி: ஆஃப்" + +#: ../src/commandhandler.cpp:521 +msgid "Player already ignored!" +msgstr "வீரர் ஏற்கனவே புறக்கணிக்கப்பட்டார்!" + +#: ../src/commandhandler.cpp:528 +msgid "Player successfully ignored!" +msgstr "வீரர் வெற்றிகரமாக புறக்கணித்தார்!" + +#: ../src/commandhandler.cpp:530 +msgid "Player could not be ignored!" +msgstr "வீரரை புறக்கணிக்க முடியவில்லை!" + +#: ../src/commandhandler.cpp:545 +msgid "Player wasn't ignored!" +msgstr "வீரர் புறக்கணிக்கப்படவில்லை!" + +#: ../src/commandhandler.cpp:550 +msgid "Player no longer ignored!" +msgstr "வீரர் இனி புறக்கணிக்கப்படவில்லை!" + +#: ../src/commandhandler.cpp:552 +msgid "Player could not be unignored!" +msgstr "வீரரை இணைக்க முடியாது!" + +#: ../src/commandhandler.h:31 +#, c-format +msgid "Options to /%s are \"yes\", \"no\", \"true\", \"false\", \"1\", \"0\"." +msgstr "" +"/%s க்கான விருப்பங்கள் \"ஆம்\", \"இல்லை\", \"உண்மை\", \"பொய்\", \"1\", \"0\"." + +#: ../src/game.cpp:167 +msgid "General" +msgstr "பொது" + +#: ../src/game.cpp:290 +msgid "Could not take screenshot!" +msgstr "திரைக்காட்சி எடுக்க முடியவில்லை!" + +#: ../src/game.cpp:328 +#, c-format +msgid "Screenshot saved as %s" +msgstr "திரைக்காட்சி %s ஆக சேமிக்கப்பட்டது" + +#: ../src/game.cpp:333 +msgid "Saving screenshot failed!" +msgstr "ச்கிரீன்சாட்டை சேமிப்பது தோல்வியடைந்தது!" + +#: ../src/game.cpp:366 +msgid "The connection to the server was lost." +msgstr "சேவையகத்திற்கான இணைப்பு இழந்தது." + +#: ../src/game.cpp:367 +msgid "Network Error" +msgstr "பிணைய பிழை" + +#: ../src/game.cpp:708 +msgid "Ignoring incoming trade requests" +msgstr "உள்வரும் வர்த்தக கோரிக்கைகளை புறக்கணித்தல்" + +#: ../src/game.cpp:713 +msgid "Accepting incoming trade requests" +msgstr "உள்வரும் வர்த்தக கோரிக்கைகளை ஏற்றுக்கொள்வது" + +#: ../src/game.cpp:941 +msgid "Could Not Load Map" +msgstr "வரைபடத்தை ஏற்ற முடியவில்லை" + +#: ../src/game.cpp:942 +#, c-format +msgid "Error while loading %s" +msgstr "%s ஐ ஏற்றும்போது பிழை" + +#: ../src/gui/beingpopup.cpp:76 +#, c-format +msgid "Party: %s" +msgstr "கட்சி: %s" + +#: ../src/gui/buydialog.cpp:48 ../src/gui/buydialog.cpp:77 +#: ../src/gui/buyselldialog.cpp:47 +msgid "Buy" +msgstr "வாங்க" + +#: ../src/gui/buydialog.cpp:68 ../src/gui/buydialog.cpp:287 +#: ../src/gui/selldialog.cpp:72 ../src/gui/selldialog.cpp:296 +#, c-format +msgid "Price: %s / Total: %s" +msgstr "விலை: %s / மொத்தம்: %s" + +#: ../src/gui/buydialog.cpp:73 ../src/gui/itemamountwindow.cpp:111 +#: ../src/gui/npcdialog.cpp:122 ../src/gui/selldialog.cpp:75 +#: ../src/gui/statuswindow.cpp:467 +msgid "+" +msgstr "+" + +#: ../src/gui/buydialog.cpp:76 ../src/gui/itemamountwindow.cpp:110 +#: ../src/gui/npcdialog.cpp:123 ../src/gui/selldialog.cpp:76 +#: ../src/gui/statuswindow.cpp:477 +msgid "-" +msgstr "-" + +#: ../src/gui/buydialog.cpp:78 ../src/gui/quitdialog.cpp:40 +#: ../src/gui/quitdialog.cpp:42 ../src/gui/quitdialog.cpp:43 +#: ../src/gui/selldialog.cpp:78 ../src/gui/serverdialog.cpp:190 +#: ../src/keyboardconfig.cpp:104 +msgid "Quit" +msgstr "வெளியேறு" + +#: ../src/gui/buydialog.cpp:79 ../src/gui/selldialog.cpp:79 +#: ../src/gui/statuswindow.cpp:394 ../src/gui/statuswindow.cpp:466 +#: ../src/gui/statuswindow.cpp:498 +msgid "Max" +msgstr "அதிகபட்சம்" + +#: ../src/gui/buyselldialog.cpp:38 +msgid "Shop" +msgstr "கடை" + +#: ../src/gui/buyselldialog.cpp:47 ../src/gui/selldialog.cpp:50 +#: ../src/gui/selldialog.cpp:77 +msgid "Sell" +msgstr "விற்கவும்" + +#: ../src/gui/buyselldialog.cpp:47 ../src/gui/changeemaildialog.cpp:55 +#: ../src/gui/changepassworddialog.cpp:58 ../src/gui/charcreatedialog.cpp:86 +#: ../src/gui/connectiondialog.cpp:44 ../src/gui/customserverdialog.cpp:76 +#: ../src/gui/itemamountwindow.cpp:113 ../src/gui/npcpostdialog.cpp:57 +#: ../src/gui/popupmenu.cpp:174 ../src/gui/popupmenu.cpp:192 +#: ../src/gui/popupmenu.cpp:393 ../src/gui/quitdialog.cpp:48 +#: ../src/gui/register.cpp:74 ../src/gui/setup.cpp:54 +#: ../src/gui/socialwindow.cpp:313 ../src/gui/textdialog.cpp:40 +#: ../src/gui/unregisterdialog.cpp:54 ../src/gui/updaterwindow.cpp:140 +msgid "Cancel" +msgstr "ரத்துசெய்" + +#: ../src/gui/changeemaildialog.cpp:45 ../src/gui/changeemaildialog.cpp:54 +msgid "Change Email Address" +msgstr "மின்னஞ்சல் முகவரியை மாற்றவும்" + +#: ../src/gui/changeemaildialog.cpp:49 ../src/gui/changepassworddialog.cpp:52 +#, c-format +msgid "Account: %s" +msgstr "கணக்கு: %s" + +#: ../src/gui/changeemaildialog.cpp:51 +msgid "Type new email address twice:" +msgstr "புதிய மின்னஞ்சல் முகவரியை இரண்டு முறை தட்டச்சு செய்க:" + +#: ../src/gui/changeemaildialog.cpp:127 +#, c-format +msgid "The new email address needs to be at least %d characters long." +msgstr "" +"புதிய மின்னஞ்சல் முகவரி குறைந்தது %d எழுத்துக்கள் நீளமாக இருக்க வேண்டும்." + +#: ../src/gui/changeemaildialog.cpp:134 +#, c-format +msgid "The new email address needs to be less than %d characters long." +msgstr "புதிய மின்னஞ்சல் முகவரி %d எழுத்துக்கள் குறைவாக இருக்க வேண்டும்." + +#: ../src/gui/changeemaildialog.cpp:141 +msgid "The email address entries mismatch." +msgstr "மின்னஞ்சல் முகவரி உள்ளீடுகள் பொருந்தவில்லை." + +#: ../src/gui/changepassworddialog.cpp:47 +#: ../src/gui/changepassworddialog.cpp:56 ../src/gui/charselectdialog.cpp:121 +msgid "Change Password" +msgstr "கடவுச்சொல்லை மாற்றவும்" + +#: ../src/gui/changepassworddialog.cpp:61 ../src/gui/logindialog.cpp:47 +#: ../src/gui/register.cpp:68 ../src/gui/unregisterdialog.cpp:51 +msgid "Password:" +msgstr "கடவுச்சொல்:" + +#: ../src/gui/changepassworddialog.cpp:63 +msgid "Type new password twice:" +msgstr "புதிய கடவுச்சொல்லை இரண்டு முறை தட்டச்சு செய்க:" + +#: ../src/gui/changepassworddialog.cpp:110 +msgid "Enter the old password first." +msgstr "முதலில் பழைய கடவுச்சொல்லை உள்ளிடவும்." + +#: ../src/gui/changepassworddialog.cpp:116 +#, c-format +msgid "The new password needs to be at least %d characters long." +msgstr "புதிய கடவுச்சொல் குறைந்தது %d எழுத்துக்கள் நீளமாக இருக்க வேண்டும்." + +#: ../src/gui/changepassworddialog.cpp:123 +#, c-format +msgid "The new password needs to be less than %d characters long." +msgstr "புதிய கடவுச்சொல் %d எழுத்துக்கள் குறைவாக இருக்க வேண்டும்." + +#: ../src/gui/changepassworddialog.cpp:130 +msgid "The new password entries mismatch." +msgstr "புதிய கடவுச்சொல் உள்ளீடுகள் பொருந்தவில்லை." + +#: ../src/gui/charcreatedialog.cpp:48 +msgid "Create Character" +msgstr "எழுத்தை உருவாக்குங்கள்" + +#: ../src/gui/charcreatedialog.cpp:71 ../src/gui/customserverdialog.cpp:56 +#: ../src/gui/logindialog.cpp:46 ../src/gui/register.cpp:67 +msgid "Name:" +msgstr "பெயர்:" + +#: ../src/gui/charcreatedialog.cpp:78 +msgid "Hair color:" +msgstr "முடி நிறம்:" + +#: ../src/gui/charcreatedialog.cpp:84 +msgid "Hair style:" +msgstr "ஏர் ச்டைல்:" + +#: ../src/gui/charcreatedialog.cpp:85 ../src/gui/charselectdialog.cpp:393 +#: ../src/gui/socialwindow.cpp:365 +msgid "Create" +msgstr "உருவாக்கு" + +#: ../src/gui/charcreatedialog.cpp:87 ../src/gui/register.cpp:90 +msgid "Male" +msgstr "ஆண்" + +#: ../src/gui/charcreatedialog.cpp:88 ../src/gui/register.cpp:91 +msgid "Female" +msgstr "பெண்" + +#: ../src/gui/charcreatedialog.cpp:106 ../src/gui/charcreatedialog.cpp:278 +#, c-format +msgid "Please distribute %d points" +msgstr "தயவுசெய்து %d புள்ளிகளை விநியோகிக்கவும்" + +#: ../src/gui/charcreatedialog.cpp:199 +msgid "Your name needs to be at least 4 characters." +msgstr "உங்கள் பெயர் குறைந்தது 4 எழுத்துகளாக இருக்க வேண்டும்." + +#: ../src/gui/charcreatedialog.cpp:269 +msgid "Character stats OK" +msgstr "எழுத்து புள்ளிவிவரங்கள் சரி" + +#: ../src/gui/charcreatedialog.cpp:283 +#, c-format +msgid "Please remove %d points" +msgstr "தயவுசெய்து %d புள்ளிகளை அகற்றவும்" + +#: ../src/gui/charselectdialog.cpp:65 +msgid "Confirm Character Delete" +msgstr "எழுத்து நீக்கு என்பதை உறுதிப்படுத்தவும்" + +#: ../src/gui/charselectdialog.cpp:66 +msgid "Are you sure you want to delete this character?" +msgstr "இந்த கதாபாத்திரத்தை நீக்க விரும்புகிறீர்களா?" + +#: ../src/gui/charselectdialog.cpp:113 +msgid "Account and Character Management" +msgstr "கணக்கு மற்றும் எழுத்து மேலாண்மை" + +#: ../src/gui/charselectdialog.cpp:120 +msgid "Switch Login" +msgstr "உள்நுழைவை மாற்றவும்" + +#: ../src/gui/charselectdialog.cpp:134 ../src/gui/unregisterdialog.cpp:45 +#: ../src/gui/unregisterdialog.cpp:53 +msgid "Unregister" +msgstr "பதிவு செய்யப்படாதது" + +#: ../src/gui/charselectdialog.cpp:143 +msgid "Change Email" +msgstr "மின்னஞ்சலை மாற்றவும்" + +#: ../src/gui/charselectdialog.cpp:340 ../src/gui/serverdialog.cpp:194 +#: ../src/gui/setup_players.cpp:221 +msgid "Delete" +msgstr "நீக்கு" + +#: ../src/gui/charselectdialog.cpp:381 +msgid "Choose" +msgstr "தேர்வு" + +#: ../src/gui/charselectdialog.cpp:395 ../src/gui/charselectdialog.cpp:396 +msgid "(empty)" +msgstr "(காலியாக)" + +#: ../src/gui/chatwindow.cpp:87 +msgid "Chat" +msgstr "அரட்டை" + +#: ../src/gui/chatwindow.cpp:302 +#, c-format +msgid "Present: %s; %d players are present." +msgstr "தற்போது: %s; %d வீரர்கள் உள்ளனர்." + +#: ../src/gui/chatwindow.cpp:320 +msgid "Attendance written to record log." +msgstr "பதிவு பதிவு செய்ய எழுதப்பட்டது." + +#: ../src/gui/chatwindow.cpp:497 +#, c-format +msgid "Whispering to %s: %s" +msgstr "%s க்கு கிசுகிசுக்கும்: %s" + +#: ../src/gui/confirmdialog.cpp:40 +msgid "Yes" +msgstr "ஆம்" + +#: ../src/gui/confirmdialog.cpp:41 +msgid "No" +msgstr "இல்லை" + +#: ../src/gui/customserverdialog.cpp:50 +msgid "Custom Server" +msgstr "தனிப்பயன் சேவையகம்" + +#: ../src/gui/customserverdialog.cpp:57 +msgid "Address:" +msgstr "முகவரி:" + +#: ../src/gui/customserverdialog.cpp:58 +msgid "Port:" +msgstr "போர்ட்:" + +#: ../src/gui/customserverdialog.cpp:60 +msgid "Server type:" +msgstr "சேவையக வகை:" + +#: ../src/gui/customserverdialog.cpp:62 +msgid "Description:" +msgstr "விளக்கம்:" + +#: ../src/gui/customserverdialog.cpp:75 +msgid "Ok" +msgstr "சரி" + +#: ../src/gui/customserverdialog.cpp:167 +msgid "Please type in at least the address of the server." +msgstr "சேவையகத்தின் முகவரியை குறைந்தபட்சம் தட்டச்சு செய்க." + +#: ../src/gui/debugwindow.cpp:55 +#, c-format +msgid "%d FPS (OpenGL)" +msgstr "%d fps (opengl)" + +#: ../src/gui/debugwindow.cpp:60 +#, c-format +msgid "%d FPS" +msgstr "%d fps" + +#: ../src/gui/debugwindow.cpp:97 +#, c-format +msgid "Cursor: (%d, %d)" +msgstr "கர்சர்: ( %d, %d)" + +#: ../src/gui/debugwindow.cpp:101 +#, c-format +msgid "Music: %s" +msgstr "இசை: %s" + +#: ../src/gui/debugwindow.cpp:102 +#, c-format +msgid "Minimap: %s" +msgstr "மினிமாப்: %s" + +#: ../src/gui/debugwindow.cpp:104 +#, c-format +msgid "Map: %s" +msgstr "வரைபடம்: %s" + +#: ../src/gui/debugwindow.cpp:108 +#, c-format +msgid "Particle count: %d" +msgstr "துகள் எண்ணிக்கை: %d" + +#: ../src/gui/debugwindow.cpp:134 +msgid "Show:" +msgstr "காட்டு:" + +#: ../src/gui/debugwindow.cpp:135 +msgid "Grid" +msgstr "வலைவாய்" + +#: ../src/gui/debugwindow.cpp:136 +msgid "Collision tiles" +msgstr "மோதல் ஓடுகள்" + +#: ../src/gui/debugwindow.cpp:137 +msgid "Being collision radius" +msgstr "மோதல் ஆரம்" + +#: ../src/gui/debugwindow.cpp:138 +msgid "Being positions" +msgstr "பதவிகள்" + +#: ../src/gui/debugwindow.cpp:139 +msgid "Being path" +msgstr "பாதை" + +#: ../src/gui/debugwindow.cpp:140 +msgid "Mouse path" +msgstr "சுட்டி பாதை" + +#: ../src/gui/debugwindow.cpp:141 +msgid "Being Ids" +msgstr "ஐடிஎச் இருப்பது" + +#: ../src/gui/debugwindow.cpp:142 +msgid "GUI debug" +msgstr "GUI பிழைத்திருத்தம்" + +#: ../src/gui/debugwindow.cpp:144 +msgid "Specials:" +msgstr "சிறப்பு:" + +#: ../src/gui/debugwindow.cpp:145 +msgid "Normal" +msgstr "சாதாரண" + +#: ../src/gui/debugwindow.cpp:146 +msgid "Special 1" +msgstr "சிறப்பு 1" + +#: ../src/gui/debugwindow.cpp:147 +msgid "Special 2" +msgstr "சிறப்பு 2" + +#: ../src/gui/debugwindow.cpp:148 +msgid "Special 3" +msgstr "சிறப்பு 3" + +#: ../src/gui/debugwindow.cpp:232 +msgid "Debug" +msgstr "பிழைத்திருத்தம்" + +#: ../src/gui/debugwindow.cpp:248 ../src/net/manaserv/charhandler.cpp:211 +#: ../src/net/tmwa/charserverhandler.cpp:148 +msgid "Info" +msgstr "தகவல்" + +#: ../src/gui/debugwindow.cpp:252 +msgid "Switches" +msgstr "சுவிட்சுகள்" + +#: ../src/gui/equipmentwindow.cpp:54 ../src/gui/windowmenu.cpp:57 +msgid "Equipment" +msgstr "உபகரணங்கள்" + +#: ../src/gui/equipmentwindow.cpp:71 ../src/gui/inventorywindow.cpp:94 +#: ../src/gui/inventorywindow.cpp:372 ../src/gui/popupmenu.cpp:365 +msgid "Unequip" +msgstr "WAKIP" + +#: ../src/gui/helpwindow.cpp:38 +msgid "Help" +msgstr "உதவி" + +#: ../src/gui/helpwindow.cpp:52 ../src/gui/npcdialog.cpp:51 +msgid "Close" +msgstr "மூடு" + +#: ../src/gui/inventorywindow.cpp:60 ../src/gui/windowmenu.cpp:55 +msgid "Inventory" +msgstr "சரக்கு" + +#: ../src/gui/inventorywindow.cpp:60 +msgid "Storage" +msgstr "சேமிப்பு" + +#: ../src/gui/inventorywindow.cpp:86 +msgid "Slots:" +msgstr "இடங்கள்:" + +#: ../src/gui/inventorywindow.cpp:87 +msgid "Search:" +msgstr "தேடல்:" + +#: ../src/gui/inventorywindow.cpp:92 ../src/gui/inventorywindow.cpp:105 +#: ../src/gui/inventorywindow.cpp:374 ../src/gui/popupmenu.cpp:367 +msgid "Equip" +msgstr "உபகரணங்கள்" + +#: ../src/gui/inventorywindow.cpp:93 +msgid "Use" +msgstr "பயன்படுத்தவும்" + +#: ../src/gui/inventorywindow.cpp:106 ../src/gui/popupmenu.cpp:370 +msgid "Activate" +msgstr "செயல்படுத்து" + +#: ../src/gui/inventorywindow.cpp:107 ../src/gui/inventorywindow.cpp:385 +#: ../src/gui/popupmenu.cpp:375 +msgid "Drop..." +msgstr "துளி ..." + +#: ../src/gui/inventorywindow.cpp:108 ../src/gui/popupmenu.cpp:382 +msgid "Split" +msgstr "பிளவு" + +#: ../src/gui/inventorywindow.cpp:109 ../src/gui/outfitwindow.cpp:42 +msgid "Outfits" +msgstr "ஆடைகள்" + +#: ../src/gui/inventorywindow.cpp:111 +msgid "Weight:" +msgstr "எடை:" + +#: ../src/gui/inventorywindow.cpp:131 ../src/gui/popupmenu.cpp:359 +msgid "Store" +msgstr "கடை" + +#: ../src/gui/inventorywindow.cpp:132 ../src/gui/popupmenu.cpp:389 +msgid "Retrieve" +msgstr "மீட்டெடுக்கவும்" + +#: ../src/gui/inventorywindow.cpp:387 ../src/gui/popupmenu.cpp:377 +msgid "Drop" +msgstr "துளி" + +#: ../src/gui/itemamountwindow.cpp:112 ../src/gui/okdialog.cpp:40 +#: ../src/gui/quitdialog.cpp:46 ../src/gui/textdialog.cpp:39 +#: ../src/gui/tradewindow.cpp:72 ../src/gui/tradewindow.cpp:74 +msgid "OK" +msgstr "சரி" + +#: ../src/gui/itemamountwindow.cpp:114 +msgid "All" +msgstr "அனைத்தும்" + +#: ../src/gui/itemamountwindow.cpp:140 +msgid "Select amount of items to trade." +msgstr "வர்த்தகத்திற்கு பொருட்களின் அளவு தேர்ந்தெடுக்கவும்." + +#: ../src/gui/itemamountwindow.cpp:143 +msgid "Select amount of items to drop." +msgstr "கைவிட உருப்படிகளின் அளவு என்பதைத் தேர்ந்தெடுக்கவும்." + +#: ../src/gui/itemamountwindow.cpp:146 +msgid "Select amount of items to store." +msgstr "சேமிக்க பொருட்களின் அளவு தேர்ந்தெடுக்கவும்." + +#: ../src/gui/itemamountwindow.cpp:149 +msgid "Select amount of items to retrieve." +msgstr "மீட்டெடுக்க பொருட்களின் அளவு என்பதைத் தேர்ந்தெடுக்கவும்." + +#: ../src/gui/itemamountwindow.cpp:152 +msgid "Select amount of items to split." +msgstr "பிரிக்க பொருட்களின் அளவு தேர்ந்தெடுக்கவும்." + +#: ../src/gui/itempopup.cpp:127 +msgid "No item" +msgstr "உருப்படி இல்லை" + +#: ../src/gui/itempopup.cpp:184 +#, c-format +msgid "Weight: %s" +msgstr "எடை: %s" + +#: ../src/gui/logindialog.cpp:43 ../src/gui/logindialog.cpp:55 +msgid "Login" +msgstr "புகுபதிவு" + +#: ../src/gui/logindialog.cpp:52 +msgid "Remember username" +msgstr "பயனர்பெயரை நினைவில் கொள்க" + +#: ../src/gui/logindialog.cpp:53 ../src/gui/register.cpp:58 +#: ../src/gui/register.cpp:73 +msgid "Register" +msgstr "பதிவு செய்யுங்கள்" + +#: ../src/gui/logindialog.cpp:54 +msgid "Change Server" +msgstr "சேவையகத்தை மாற்றவும்" + +#: ../src/gui/logindialog.cpp:119 +msgid "Registration disabled" +msgstr "பதிவு முடக்கப்பட்டது" + +#: ../src/gui/logindialog.cpp:119 +msgid "You need to use the website to register an account for this server." +msgstr "" +"இந்த சேவையகத்திற்கான கணக்கை பதிவு செய்ய நீங்கள் வலைத்தளத்தைப் பயன்படுத்த வேண்டும்." + +#: ../src/gui/minimap.cpp:45 ../src/gui/minimap.cpp:79 +msgid "Map" +msgstr "வரைபடம்" + +#: ../src/gui/ministatuswindow.cpp:244 +msgid "Need" +msgstr "தேவை" + +#: ../src/gui/npcdialog.cpp:49 +msgid "Waiting for server" +msgstr "சேவையகத்திற்காக காத்திருக்கிறது" + +#: ../src/gui/npcdialog.cpp:50 +msgid "Next" +msgstr "அடுத்தது" + +#: ../src/gui/npcdialog.cpp:52 +msgid "Submit" +msgstr "சமர்ப்பிக்கவும்" + +#: ../src/gui/npcdialog.cpp:72 ../src/gui/npcpostdialog.cpp:41 +msgid "NPC" +msgstr "NPC" + +#: ../src/gui/npcdialog.cpp:116 +msgid "Clear log" +msgstr "பதிவை அழிக்கவும்" + +#: ../src/gui/npcdialog.cpp:132 +msgid "Reset" +msgstr "மீட்டமை" + +#: ../src/gui/npcpostdialog.cpp:47 +msgid "To:" +msgstr "இதற்கு:" + +#: ../src/gui/npcpostdialog.cpp:54 +msgid "Send" +msgstr "அனுப்பு" + +#: ../src/gui/npcpostdialog.cpp:99 +msgid "Failed to send as sender or letter invalid." +msgstr "அனுப்புநராக அல்லது கடிதத்தை செல்லாதது தவறானது." + +#: ../src/gui/outfitwindow.cpp:49 +msgid "<" +msgstr "<" + +#: ../src/gui/outfitwindow.cpp:50 +msgid ">" +msgstr ">" + +#: ../src/gui/outfitwindow.cpp:51 ../src/gui/outfitwindow.cpp:120 +#: ../src/gui/outfitwindow.cpp:133 +#, c-format +msgid "Outfit: %d" +msgstr "ஆடை: %d" + +#: ../src/gui/outfitwindow.cpp:53 +msgid "Unequip first" +msgstr "முதலில்" + +#: ../src/gui/popupmenu.cpp:79 +#, c-format +msgid "Trade with %s..." +msgstr "%s உடன் வணிகம் ..." + +#: ../src/gui/popupmenu.cpp:83 ../src/gui/popupmenu.cpp:157 +#, c-format +msgid "Attack %s" +msgstr "தாக்குதல் %s" + +#: ../src/gui/popupmenu.cpp:87 +#, c-format +msgid "Whisper %s" +msgstr "விச்பர் %s" + +#: ../src/gui/popupmenu.cpp:96 +#, c-format +msgid "Befriend %s" +msgstr "நட்பு %s" + +#: ../src/gui/popupmenu.cpp:101 +#, c-format +msgid "Disregard %s" +msgstr "%s புறக்கணிக்கவும்" + +#: ../src/gui/popupmenu.cpp:104 +#, c-format +msgid "Ignore %s" +msgstr "%s புறக்கணிக்கவும்" + +#: ../src/gui/popupmenu.cpp:110 ../src/gui/popupmenu.cpp:119 +#, c-format +msgid "Unignore %s" +msgstr "Uniginore %s" + +#: ../src/gui/popupmenu.cpp:113 +#, c-format +msgid "Completely ignore %s" +msgstr "%s ஐ முற்றிலும் புறக்கணிக்கவும்" + +#: ../src/gui/popupmenu.cpp:126 +#, c-format +msgid "Invite %s to join your guild" +msgstr "உங்கள் கில்டில் சேர %s ஐ அழைக்கவும்" + +#: ../src/gui/popupmenu.cpp:132 +#, c-format +msgid "Invite %s to join your party" +msgstr "உங்கள் கட்சியில் சேர %s ஐ அழைக்கவும்" + +#: ../src/gui/popupmenu.cpp:140 +msgid "Kick player" +msgstr "கிக் பிளேயர்" + +#: ../src/gui/popupmenu.cpp:149 +#, c-format +msgid "Talk to %s" +msgstr "%s உடன் பேசுங்கள்" + +#: ../src/gui/popupmenu.cpp:162 +msgid "Kick monster" +msgstr "மான்ச்டர் கிக்" + +#: ../src/gui/popupmenu.cpp:170 +msgid "Add name to chat" +msgstr "அரட்டைக்கு பெயரைச் சேர்க்கவும்" + +#: ../src/gui/popupmenu.cpp:186 +#, c-format +msgid "Pick up %s" +msgstr "%s ஐ எடுக்கவும்" + +#: ../src/gui/popupmenu.cpp:188 ../src/gui/popupmenu.cpp:391 +msgid "Add to chat" +msgstr "அரட்டையில் சேர்க்கவும்" + +#: ../src/gui/quitdialog.cpp:44 +msgid "Switch server" +msgstr "சேவையகம் சுவிட்ச்" + +#: ../src/gui/quitdialog.cpp:45 +msgid "Switch character" +msgstr "எழுத்துக்குறி சுவிட்ச்" + +#: ../src/gui/recorder.cpp:87 +msgid "Finishing recording." +msgstr "பதிவு முடித்தல்." + +#: ../src/gui/recorder.cpp:91 +msgid "Not currently recording." +msgstr "தற்போது பதிவு செய்யவில்லை." + +#: ../src/gui/recorder.cpp:96 +msgid "Already recording." +msgstr "ஏற்கனவே பதிவுசெய்கிறது." + +#: ../src/gui/recorder.cpp:104 +msgid "Starting to record..." +msgstr "பதிவு செய்யத் தொடங்குகிறது ..." + +#: ../src/gui/recorder.cpp:112 +msgid "Failed to start recording." +msgstr "பதிவு செய்யத் தவறிவிட்டது." + +#: ../src/gui/recorder.h:39 +msgid "Recording..." +msgstr "பதிவு செய்தல் ..." + +#: ../src/gui/recorder.h:40 +msgid "Stop recording" +msgstr "பதிவு செய்வதை நிறுத்துங்கள்" + +#: ../src/gui/register.cpp:69 +msgid "Confirm:" +msgstr "உறுதிப்படுத்தவும்:" + +#: ../src/gui/register.cpp:100 +msgid "Email:" +msgstr "மின்னஞ்சல்:" + +#: ../src/gui/register.cpp:166 +#, c-format +msgid "The username needs to be at least %d characters long." +msgstr "பயனர்பெயர் குறைந்தது %d எழுத்துக்கள் நீளமாக இருக்க வேண்டும்." + +#: ../src/gui/register.cpp:174 +#, c-format +msgid "The username needs to be less than %d characters long." +msgstr "பயனர்பெயர் %d கதாபாத்திரங்களுக்கும் குறைவாக இருக்க வேண்டும்." + +#: ../src/gui/register.cpp:182 ../src/gui/unregisterdialog.cpp:114 +#, c-format +msgid "The password needs to be at least %d characters long." +msgstr "கடவுச்சொல் குறைந்தது %d எழுத்துக்கள் நீளமாக இருக்க வேண்டும்." + +#: ../src/gui/register.cpp:190 ../src/gui/unregisterdialog.cpp:121 +#, c-format +msgid "The password needs to be less than %d characters long." +msgstr "கடவுச்சொல் %d எழுத்துக்கள் குறைவாக இருக்க வேண்டும்." + +#: ../src/gui/register.cpp:197 +msgid "Passwords do not match." +msgstr "கடவுச்சொற்கள் பொருந்தவில்லை." + +#: ../src/gui/serverdialog.cpp:172 +msgid "Choose Your Server" +msgstr "உங்கள் சேவையகத்தைத் தேர்வுசெய்க" + +#: ../src/gui/serverdialog.cpp:191 +msgid "Connect" +msgstr "இணை" + +#: ../src/gui/serverdialog.cpp:192 +msgid "Add custom Server..." +msgstr "தனிப்பயன் சேவையகத்தைச் சேர்க்கவும் ..." + +#: ../src/gui/serverdialog.cpp:193 +msgid "Modify..." +msgstr "மாற்றவும் ..." + +#: ../src/gui/serverdialog.cpp:272 +msgid "Please select a valid server." +msgstr "செல்லுபடியாகும் சேவையகத்தைத் தேர்ந்தெடுக்கவும்." + +#: ../src/gui/serverdialog.cpp:316 +msgid "Please select a custom server." +msgstr "தனிப்பயன் சேவையகத்தைத் தேர்ந்தெடுக்கவும்." + +#: ../src/gui/serverdialog.cpp:389 +#, c-format +msgid "Downloading server list...%2.2f%%" +msgstr "சேவையக பட்டியலைப் பதிவிறக்குகிறது ...%2.2f %%" + +#: ../src/gui/serverdialog.cpp:395 +msgid "Waiting for server..." +msgstr "சேவையகத்திற்காக காத்திருக்கிறது ..." + +#: ../src/gui/serverdialog.cpp:399 +msgid "Preparing download" +msgstr "பதிவிறக்கத்தைத் தயாரித்தல்" + +#: ../src/gui/serverdialog.cpp:403 +msgid "Error retreiving server list!" +msgstr "சேவையக பட்டியலை மீட்டெடுப்பதில் பிழை!" + +#: ../src/gui/serverdialog.cpp:480 +msgid "requires a newer version" +msgstr "புதிய பதிப்பு தேவை" + +#: ../src/gui/serverdialog.cpp:482 +#, c-format +msgid "requires v%s" +msgstr "v%s தேவை" + +#: ../src/gui/setup_audio.cpp:42 +msgid "Sound" +msgstr "ஒலி" + +#: ../src/gui/setup_audio.cpp:43 +msgid "Download music" +msgstr "இசையைப் பதிவிறக்கவும்" + +#: ../src/gui/setup_audio.cpp:48 +msgid "Audio" +msgstr "ஆடியோ" + +#: ../src/gui/setup_audio.cpp:50 +msgid "SFX volume" +msgstr "SFX தொகுதி" + +#: ../src/gui/setup_audio.cpp:51 +msgid "Notifications volume" +msgstr "அறிவிப்புகள் தொகுதி" + +#: ../src/gui/setup_audio.cpp:52 +msgid "Music volume" +msgstr "இசை தொகுதி" + +#: ../src/gui/setup_audio.cpp:97 +msgid "Notice" +msgstr "அறிவிப்பு" + +#: ../src/gui/setup_audio.cpp:97 +msgid "You may have to restart your client if you want to download new music" +msgstr "" +"புதிய இசையைப் பதிவிறக்க விரும்பினால் உங்கள் வாடிக்கையாளரை மறுதொடக்கம் செய்ய " +"வேண்டியிருக்கும்" + +#: ../src/gui/setup_audio.cpp:109 +msgid "Sound Engine" +msgstr "ஒலி இயந்திரம்" + +#: ../src/gui/setup_colors.cpp:43 +msgid "This is what the color looks like" +msgstr "இதுதான் நிறம் போல் தெரிகிறது" + +#: ../src/gui/setup_colors.cpp:48 +msgid "Colors" +msgstr "நிறங்கள்" + +#: ../src/gui/setup_colors.cpp:65 +msgid "Type:" +msgstr "தட்டச்சு:" + +#: ../src/gui/setup_colors.cpp:76 ../src/gui/setup_colors.cpp:319 +msgid "Static" +msgstr "நிலையான" + +#: ../src/gui/setup_colors.cpp:78 ../src/gui/setup_colors.cpp:79 +#: ../src/gui/setup_colors.cpp:320 +msgid "Pulse" +msgstr "நாடி" + +#: ../src/gui/setup_colors.cpp:80 ../src/gui/setup_colors.cpp:81 +#: ../src/gui/setup_colors.cpp:321 +msgid "Rainbow" +msgstr "ரெயின்போ" + +#: ../src/gui/setup_colors.cpp:82 ../src/gui/setup_colors.cpp:83 +#: ../src/gui/setup_colors.cpp:321 +msgid "Spectrum" +msgstr "நிறமாலை" + +#: ../src/gui/setup_colors.cpp:87 +msgid "Delay:" +msgstr "தாமதம்:" + +#: ../src/gui/setup_colors.cpp:102 +msgid "Red:" +msgstr "சிவப்பு:" + +#: ../src/gui/setup_colors.cpp:117 +msgid "Green:" +msgstr "பச்சை:" + +#: ../src/gui/setup_colors.cpp:132 +msgid "Blue:" +msgstr "நீலம்:" + +#: ../src/gui/setup.cpp:54 +msgid "Apply" +msgstr "இடு" + +#: ../src/gui/setup.cpp:54 +msgid "Reset Windows" +msgstr "சாளரங்களை மீட்டமைக்கவும்" + +#: ../src/gui/setup_interface.cpp:44 +msgid "Tiny" +msgstr "சிறிய" + +#: ../src/gui/setup_interface.cpp:45 +msgid "Small" +msgstr "சிறிய" + +#: ../src/gui/setup_interface.cpp:46 +msgid "Medium" +msgstr "சராசரி" + +#: ../src/gui/setup_interface.cpp:47 +msgid "Large" +msgstr "பெரிய" + +#: ../src/gui/setup_interface.cpp:61 ../src/gui/setup_players.cpp:198 +msgid "???" +msgstr "???" + +#: ../src/gui/setup_interface.cpp:71 +msgid "No text" +msgstr "உரை இல்லை" + +#: ../src/gui/setup_interface.cpp:72 +msgid "Text" +msgstr "உரை" + +#: ../src/gui/setup_interface.cpp:73 +msgid "Bubbles, no names" +msgstr "குமிழ்கள், பெயர்கள் இல்லை" + +#: ../src/gui/setup_interface.cpp:74 +msgid "Bubbles with names" +msgstr "பெயர்களுடன் குமிழ்கள்" + +#: ../src/gui/setup_interface.cpp:88 +msgid "Visible names" +msgstr "புலப்படும் பெயர்கள்" + +#: ../src/gui/setup_interface.cpp:90 +msgid "Show own name" +msgstr "சொந்த பெயரைக் காட்டு" + +#: ../src/gui/setup_interface.cpp:91 +msgid "Log NPC dialogue" +msgstr "பதிவு NPC உரையாடல்" + +#: ../src/gui/setup_interface.cpp:92 +msgid "Show pickup notification:" +msgstr "இடும் அறிவிப்பைக் காட்டு:" + +#: ../src/gui/setup_interface.cpp:94 +msgid "in chat" +msgstr "அரட்டையில்" + +#: ../src/gui/setup_interface.cpp:96 +msgid "as particle" +msgstr "துகள்" + +#: ../src/gui/setup_interface.cpp:103 +msgid "Interface" +msgstr "இடைமுகம்" + +#: ../src/gui/setup_interface.cpp:108 +msgid "Show damage" +msgstr "சேதத்தைக் காட்டு" + +#: ../src/gui/setup_interface.cpp:111 +msgid "Overhead text:" +msgstr "மேல்நிலை உரை:" + +#: ../src/gui/setup_interface.cpp:112 +msgid "GUI opacity" +msgstr "GUI ஒளிபுகா" + +#: ../src/gui/setup_interface.cpp:113 +msgid "Font size:" +msgstr "எழுத்துரு அளவு:" + +#: ../src/gui/setup_joystick.cpp:36 ../src/gui/setup_joystick.cpp:70 +msgid "Press the button to start calibration" +msgstr "அளவுத்திருத்தத்தைத் தொடங்க பொத்தானை அழுத்தவும்" + +#: ../src/gui/setup_joystick.cpp:37 ../src/gui/setup_joystick.cpp:68 +msgid "Calibrate" +msgstr "அளவீடு செய்யுங்கள்" + +#: ../src/gui/setup_joystick.cpp:38 +msgid "Enable joystick" +msgstr "சாய்ச்டிக் இயக்கு" + +#: ../src/gui/setup_joystick.cpp:40 +msgid "Joystick" +msgstr "இயக்குப்பிடி" + +#: ../src/gui/setup_joystick.cpp:75 +msgid "Stop" +msgstr "நிறுத்து" + +#: ../src/gui/setup_joystick.cpp:76 +msgid "Rotate the stick" +msgstr "குச்சியை சுழற்றுங்கள்" + +#: ../src/gui/setup_keyboard.cpp:79 +msgid "Keyboard" +msgstr "விசைப்பலகை" + +#: ../src/gui/setup_keyboard.cpp:89 +msgid "Assign" +msgstr "ஒதுக்க" + +#: ../src/gui/setup_keyboard.cpp:93 +msgid "Unassign" +msgstr "ஒதுக்கவும்" + +#: ../src/gui/setup_keyboard.cpp:97 +msgid "Default" +msgstr "இயல்புநிலை" + +#: ../src/gui/setup_keyboard.cpp:123 +msgid "Key Conflict(s) Detected." +msgstr "முக்கிய மோதல் (கள்) கண்டறியப்பட்டது." + +#: ../src/gui/setup_players.cpp:55 +msgid "Name" +msgstr "பெயர்" + +#: ../src/gui/setup_players.cpp:56 +msgid "Relation" +msgstr "உறவு" + +#: ../src/gui/setup_players.cpp:61 +msgid "Neutral" +msgstr "நடுநிலை" + +#: ../src/gui/setup_players.cpp:62 +msgid "Friend" +msgstr "நண்பர்" + +#: ../src/gui/setup_players.cpp:63 +msgid "Disregarded" +msgstr "புறக்கணிக்கப்பட்டது" + +#: ../src/gui/setup_players.cpp:64 +msgid "Ignored" +msgstr "புறக்கணிக்கப்பட்டது" + +#: ../src/gui/setup_players.cpp:217 +msgid "Allow trading" +msgstr "வர்த்தகத்தை அனுமதிக்கவும்" + +#: ../src/gui/setup_players.cpp:219 +msgid "Allow whispers" +msgstr "கிசுகிசுக்களை அனுமதிக்கவும்" + +#: ../src/gui/setup_players.cpp:223 +msgid "Put all whispers in tabs" +msgstr "அனைத்து கிசுகிசுக்களையும் தாவல்களில் வைக்கவும்" + +#: ../src/gui/setup_players.cpp:225 +msgid "Show gender" +msgstr "பாலினத்தைக் காட்டு" + +#: ../src/gui/setup_players.cpp:227 +msgid "Enable Chat log" +msgstr "அரட்டை பதிவை இயக்கவும்" + +#: ../src/gui/setup_players.cpp:229 +msgid "Players" +msgstr "வீரர்கள்" + +#: ../src/gui/setup_players.cpp:254 +msgid "When ignoring:" +msgstr "புறக்கணிக்கும்போது:" + +#: ../src/gui/setup_video.cpp:102 +msgid "Custom" +msgstr "தனிப்பயன்" + +#: ../src/gui/setup_video.cpp:176 +#, c-format +msgid "Auto (%dx)" +msgstr "ஆட்டோ (%dஎக்ச்)" + +#: ../src/gui/setup_video.cpp:178 +#, c-format +msgid "%dx" +msgstr "%d.எக்ச்" + +#: ../src/gui/setup_video.cpp:193 +msgid "off" +msgstr "அணை" + +#: ../src/gui/setup_video.cpp:194 ../src/gui/setup_video.cpp:207 +msgid "low" +msgstr "குறைந்த" + +#: ../src/gui/setup_video.cpp:195 ../src/gui/setup_video.cpp:209 +msgid "high" +msgstr "உயர்ந்த" + +#: ../src/gui/setup_video.cpp:208 +msgid "medium" +msgstr "சராசரி" + +#: ../src/gui/setup_video.cpp:210 +msgid "max" +msgstr "அதிகபட்சம்" + +#: ../src/gui/setup_video.cpp:221 +msgid "Windowed" +msgstr "சாளரம்" + +#: ../src/gui/setup_video.cpp:221 +msgid "Windowed Fullscreen" +msgstr "சாளர முழு திரை" + +#: ../src/gui/setup_video.cpp:221 +msgid "Fullscreen" +msgstr "முழு திரை" + +#: ../src/gui/setup_video.cpp:227 +msgid "VSync" +msgstr "Vsync" + +#: ../src/gui/setup_video.cpp:228 +msgid "OpenGL (Legacy)" +msgstr "Opengl (மரபு)" + +#: ../src/gui/setup_video.cpp:229 +msgid "Custom cursor" +msgstr "தனிப்பயன் கர்சர்" + +#: ../src/gui/setup_video.cpp:230 +msgid "Particle effects" +msgstr "துகள் விளைவுகள்" + +#: ../src/gui/setup_video.cpp:231 +msgid "FPS limit:" +msgstr "FPS வரம்பு:" + +#: ../src/gui/setup_video.cpp:241 +msgid "Disable transparency (Low CPU mode)" +msgstr "வெளிப்படைத்தன்மையை முடக்கு (குறைந்த சிபியு பயன்முறை)" + +#: ../src/gui/setup_video.cpp:244 +msgid "Video" +msgstr "ஒளிதோற்றம்" + +#: ../src/gui/setup_video.cpp:246 +msgid "Ambient FX:" +msgstr "சுற்றுப்புற எஃப்எக்ச்:" + +#: ../src/gui/setup_video.cpp:247 +msgid "Particle detail:" +msgstr "துகள் விவரம்:" + +#: ../src/gui/setup_video.cpp:253 ../src/gui/setup_video.cpp:450 +#: ../src/gui/setup_video.cpp:525 +msgid "None" +msgstr "எதுவுமில்லை" + +#: ../src/gui/setup_video.cpp:311 +msgid "Window mode:" +msgstr "சாளரம் பயன்முறை:" + +#: ../src/gui/setup_video.cpp:313 +msgid "Resolution:" +msgstr "தீர்மானம்:" + +#: ../src/gui/setup_video.cpp:315 +msgid "Scale:" +msgstr "அளவு:" + +#: ../src/gui/setup_video.cpp:374 +msgid "Failed to change video mode." +msgstr "வீடியோ பயன்முறையை மாற்றுவதில் தோல்வி." + +#: ../src/gui/setup_video.cpp:385 +msgid "Changing to OpenGL" +msgstr "OpenGL க்கு மாறுகிறது" + +#: ../src/gui/setup_video.cpp:386 +msgid "" +"Applying change to OpenGL requires restart.\n" +"\n" +"In case OpenGL messes up your game graphics, restart the game with the " +"command line option \"--no-opengl\"." +msgstr "" +"OpenGL க்கு மாற்றத்தைப் பயன்படுத்துவதற்கு மறுதொடக்கம் தேவை.\n" +"\n" +" ஓபன்சிஎல் உங்கள் விளையாட்டு கிராபிக்ச் குழப்பமடைந்தால், கட்டளை வரி விருப்பத்துடன் " +"விளையாட்டை மறுதொடக்கம் செய்யுங்கள் \"-இல்லை-ஓபெங்\"." + +#: ../src/gui/setup_video.cpp:393 +msgid "Deactivating OpenGL" +msgstr "Opengl ஐ செயலிழக்கச் செய்தல்" + +#: ../src/gui/setup_video.cpp:394 +msgid "Applying change to OpenGL requires restart." +msgstr "OpenGL க்கு மாற்றத்தைப் பயன்படுத்துவதற்கு மறுதொடக்கம் தேவை." + +#: ../src/gui/setup_video.cpp:402 +msgid "Transparency disabled" +msgstr "வெளிப்படைத்தன்மை முடக்கப்பட்டது" + +#: ../src/gui/setup_video.cpp:403 ../src/gui/setup_video.cpp:411 +msgid "You must restart to apply changes." +msgstr "மாற்றங்களைப் பயன்படுத்த நீங்கள் மறுதொடக்கம் செய்ய வேண்டும்." + +#: ../src/gui/setup_video.cpp:410 +msgid "Transparency enabled" +msgstr "வெளிப்படைத்தன்மை இயக்கப்பட்டது" + +#: ../src/gui/setup_video.cpp:503 +msgid "Particle Effect Settings Changed." +msgstr "துகள் விளைவு அமைப்புகள் மாற்றப்பட்டன." + +#: ../src/gui/setup_video.cpp:504 +msgid "Changes will take effect on map change." +msgstr "மாற்றங்கள் வரைபட மாற்றத்தில் நடைமுறைக்கு வரும்." + +#: ../src/gui/skilldialog.cpp:205 ../src/gui/windowmenu.cpp:61 +msgid "Skills" +msgstr "திறன்கள்" + +#: ../src/gui/skilldialog.cpp:220 +msgid "Up" +msgstr "மேலே" + +#: ../src/gui/skilldialog.cpp:265 +#, c-format +msgid "Skill points available: %d" +msgstr "திறன் புள்ளிகள் கிடைக்கின்றன: %d" + +#: ../src/gui/skilldialog.cpp:366 +#, c-format +msgid "Skill Set %d" +msgstr "திறன் தொகுப்பு %d" + +#: ../src/gui/skilldialog.cpp:375 +#, c-format +msgid "Skill %d" +msgstr "திறன் %d" + +#: ../src/gui/skilldialog.cpp:457 +#, c-format +msgid "Lvl: %d (%+d)" +msgstr "எல்விஎல்: %d (%+d)" + +#: ../src/gui/skilldialog.cpp:468 +#, c-format +msgid "Lvl: %d" +msgstr "எல்விஎல்: %d" + +#: ../src/gui/socialwindow.cpp:116 +#, c-format +msgid "Invited user %s to guild %s." +msgstr "கில்ட் %s பயனர் %s அழைக்கப்பட்டன." + +#: ../src/gui/socialwindow.cpp:129 +#, c-format +msgid "Guild %s quit requested." +msgstr "கில்ட் %s கோரப்பட்டன." + +#: ../src/gui/socialwindow.cpp:143 +msgid "Member Invite to Guild" +msgstr "உறுப்பினர் கில்டுக்கு அழைப்பு" + +#: ../src/gui/socialwindow.cpp:144 +#, c-format +msgid "Who would you like to invite to guild %s?" +msgstr "கில்ட் %s யாருக்கு அழைக்க விரும்புகிறீர்கள்?" + +#: ../src/gui/socialwindow.cpp:153 +msgid "Leave Guild?" +msgstr "கில்ட்டை விட்டு வெளியேறவா?" + +#: ../src/gui/socialwindow.cpp:154 +#, c-format +msgid "Are you sure you want to leave guild %s?" +msgstr "கில்ட் %s விட்டு வெளியேற விரும்புகிறீர்களா?" + +#: ../src/gui/socialwindow.cpp:189 ../src/net/tmwa/partyhandler.cpp:318 +#, c-format +msgid "Invited user %s to party." +msgstr "கட்சிக்கு பயனர் %s அழைக்கப்பட்டன." + +#: ../src/gui/socialwindow.cpp:200 +#, c-format +msgid "Party %s quit requested." +msgstr "கட்சி %s கோரப்பட்டன." + +#: ../src/gui/socialwindow.cpp:214 +msgid "Member Invite to Party" +msgstr "உறுப்பினர் கட்சிக்கு அழைப்பு விடுங்கள்" + +#: ../src/gui/socialwindow.cpp:215 +#, c-format +msgid "Who would you like to invite to party %s?" +msgstr "கட்சி %s யாருக்கு அழைக்க விரும்புகிறீர்கள்?" + +#: ../src/gui/socialwindow.cpp:224 +msgid "Leave Party?" +msgstr "விருந்து விடலாமா?" + +#: ../src/gui/socialwindow.cpp:225 +#, c-format +msgid "Are you sure you want to leave party %s?" +msgstr "கட்சி%s விட்டுவிட விரும்புகிறீர்களா?" + +#: ../src/gui/socialwindow.cpp:310 +msgid "Create Guild" +msgstr "கில்ட் உருவாக்கு" + +#: ../src/gui/socialwindow.cpp:311 ../src/gui/socialwindow.cpp:661 +msgid "Create Party" +msgstr "கட்சியை உருவாக்குங்கள்" + +#: ../src/gui/socialwindow.cpp:350 ../src/gui/windowmenu.cpp:67 +msgid "Social" +msgstr "சமூக" + +#: ../src/gui/socialwindow.cpp:366 +msgid "Invite" +msgstr "அழைக்கவும்" + +#: ../src/gui/socialwindow.cpp:367 +msgid "Leave" +msgstr "விடுப்பு" + +#: ../src/gui/socialwindow.cpp:380 ../src/gui/socialwindow.cpp:676 +#, c-format +msgid "Online (%zu)" +msgstr "நிகழ்நிலை (%zu)" + +#: ../src/gui/socialwindow.cpp:485 +#, c-format +msgid "Accepted party invite from %s." +msgstr "ஏற்றுக்கொள்ளப்பட்ட கட்சி %s இலிருந்து அழைப்பு." + +#: ../src/gui/socialwindow.cpp:491 +#, c-format +msgid "Rejected party invite from %s." +msgstr "நிராகரிக்கப்பட்ட கட்சி %s இலிருந்து அழைப்பு." + +#: ../src/gui/socialwindow.cpp:504 +msgid "Accepted guild invite" +msgstr "ஏற்றுக்கொள்ளப்பட்ட கில்ட் அழைப்பு" + +#: ../src/gui/socialwindow.cpp:509 +msgid "Rejected guild invite." +msgstr "நிராகரிக்கப்பட்ட கில்ட் அழைப்பு." + +#: ../src/gui/socialwindow.cpp:537 +msgid "Creating guild failed, please choose a shorter name." +msgstr "" +"கில்ட்டை உருவாக்குவது தோல்வியுற்றது, தயவுசெய்து குறுகிய பெயரைத் தேர்வுசெய்க." + +#: ../src/gui/socialwindow.cpp:545 +#, c-format +msgid "Creating guild called %s." +msgstr "கில்ட்டை உருவாக்குதல் %s என்று அழைக்கப்படுகிறது." + +#: ../src/gui/socialwindow.cpp:561 +msgid "Creating party failed, please choose a shorter name." +msgstr "" +"கட்சியை உருவாக்குவது தோல்வியுற்றது, தயவுசெய்து குறுகிய பெயரைத் தேர்வுசெய்க." + +#: ../src/gui/socialwindow.cpp:569 +#, c-format +msgid "Creating party called %s." +msgstr "%s எனப்படும் கட்சியை உருவாக்குதல்." + +#: ../src/gui/socialwindow.cpp:583 +msgid "Guild Name" +msgstr "கில்ட் பெயர்" + +#: ../src/gui/socialwindow.cpp:584 +msgid "Choose your guild's name." +msgstr "உங்கள் கில்ட்டின் பெயரைத் தேர்வுசெய்க." + +#: ../src/gui/socialwindow.cpp:596 +msgid "Received guild request, but one already exists." +msgstr "கில்ட் கோரிக்கையைப் பெற்றது, ஆனால் ஒன்று ஏற்கனவே உள்ளது." + +#: ../src/gui/socialwindow.cpp:600 +#, c-format +msgid "%s has invited you to join the guild %s." +msgstr "கில்ட் %s சேர %s உங்களை அழைத்தது." + +#: ../src/gui/socialwindow.cpp:605 +msgid "Accept Guild Invite" +msgstr "கில்ட் அழைப்பை ஏற்றுக்கொள்ளுங்கள்" + +#: ../src/gui/socialwindow.cpp:617 +msgid "Received party request, but one already exists." +msgstr "கட்சி கோரிக்கையைப் பெற்றது, ஆனால் ஒன்று ஏற்கனவே உள்ளது." + +#: ../src/gui/socialwindow.cpp:626 +msgid "You have been invited you to join a party." +msgstr "ஒரு விருந்தில் சேர உங்களை அழைத்தீர்கள்." + +#: ../src/gui/socialwindow.cpp:630 +#, c-format +msgid "You have been invited to join the %s party." +msgstr "%s கட்சியில் சேர நீங்கள் அழைக்கப்பட்டுள்ளீர்கள்." + +#: ../src/gui/socialwindow.cpp:638 +#, c-format +msgid "%s has invited you to join their party." +msgstr "%s தங்கள் கட்சியில் சேர உங்களை அழைத்துள்ளன." + +#: ../src/gui/socialwindow.cpp:643 +#, c-format +msgid "%s has invited you to join the %s party." +msgstr "%s உங்களை %s கட்சியில் சேர அழைத்தார்." + +#: ../src/gui/socialwindow.cpp:651 +msgid "Accept Party Invite" +msgstr "கட்சி அழைப்பை ஏற்றுக்கொள்ளுங்கள்" + +#: ../src/gui/socialwindow.cpp:662 +msgid "Cannot create party. You are already in a party." +msgstr "" +"கட்சியை உருவாக்க முடியாது. நீங்கள் ஏற்கனவே ஒரு விருந்தில் இருக்கிறீர்கள்." + +#: ../src/gui/socialwindow.cpp:667 +msgid "Party Name" +msgstr "கட்சி பெயர்" + +#: ../src/gui/socialwindow.cpp:668 +msgid "Choose your party's name." +msgstr "உங்கள் கட்சியின் பெயரைத் தேர்வுசெய்க." + +#: ../src/gui/specialswindow.cpp:69 ../src/gui/windowmenu.cpp:65 +msgid "Specials" +msgstr "சிறப்பு" + +#: ../src/gui/statuswindow.cpp:116 ../src/gui/statuswindow.cpp:218 +#: ../src/gui/statuswindow.cpp:266 +#, c-format +msgid "Level: %d" +msgstr "நிலை: %d" + +#: ../src/gui/statuswindow.cpp:117 ../src/gui/statuswindow.cpp:211 +#: ../src/gui/statuswindow.cpp:243 +#, c-format +msgid "Money: %s" +msgstr "பணம்: %s" + +#: ../src/gui/statuswindow.cpp:120 +msgid "HP:" +msgstr "எச்பி:" + +#: ../src/gui/statuswindow.cpp:125 +msgid "Exp:" +msgstr "எக்ச்ப்:" + +#: ../src/gui/statuswindow.cpp:133 +msgid "MP:" +msgstr "எம்.பி.:" + +#: ../src/gui/statuswindow.cpp:161 ../src/gui/statuswindow.cpp:279 +#, c-format +msgid "Job: %d" +msgstr "வேலை: %d" + +#: ../src/gui/statuswindow.cpp:162 +msgid "Job:" +msgstr "வேலை:" + +#: ../src/gui/statuswindow.cpp:214 ../src/gui/statuswindow.cpp:251 +#, c-format +msgid "Character points: %d" +msgstr "எழுத்து புள்ளிகள்: %d" + +#: ../src/gui/statuswindow.cpp:259 +#, c-format +msgid "Correction points: %d" +msgstr "திருத்தம் புள்ளிகள்: %d" + +#: ../src/gui/tradewindow.cpp:53 +msgid "Propose trade" +msgstr "வர்த்தகத்தை முன்மொழியுங்கள்" + +#: ../src/gui/tradewindow.cpp:54 +msgid "Confirmed. Waiting..." +msgstr "உறுதிப்படுத்தப்பட்டது. காத்திருக்கிறது ..." + +#: ../src/gui/tradewindow.cpp:55 +msgid "Agree trade" +msgstr "வர்த்தகத்தை ஒப்புக்கொள்கிறேன்" + +#: ../src/gui/tradewindow.cpp:56 +msgid "Agreed. Waiting..." +msgstr "ஒப்புக்கொண்டார். காத்திருக்கிறது ..." + +#: ../src/gui/tradewindow.cpp:59 +msgid "Trade: You" +msgstr "வர்த்தகம்: நீங்கள்" + +#: ../src/gui/tradewindow.cpp:73 ../src/gui/tradewindow.cpp:74 +msgid "Trade" +msgstr "வணிகம்" + +#: ../src/gui/tradewindow.cpp:76 +msgid "Add" +msgstr "கூட்டு" + +#: ../src/gui/tradewindow.cpp:98 ../src/gui/tradewindow.cpp:134 +#, c-format +msgid "You get %s" +msgstr "நீங்கள் %s பெறுவீர்கள்" + +#: ../src/gui/tradewindow.cpp:99 +msgid "You give:" +msgstr "நீங்கள் கொடுங்கள்:" + +#: ../src/gui/tradewindow.cpp:103 +msgid "Change" +msgstr "மாற்றம்" + +#: ../src/gui/tradewindow.cpp:262 +msgid "Failed adding item. You cannot overlap one kind of item on the window." +msgstr "" +"உருப்படியைச் சேர்ப்பதில் தோல்வி. சாளரத்தில் ஒரு வகையான உருப்படியை நீங்கள் ஒன்றுடன் ஒன்று " +"சேர்க்க முடியாது." + +#: ../src/gui/tradewindow.cpp:303 +msgid "You don't have enough money." +msgstr "உங்களிடம் போதுமான பணம் இல்லை." + +#: ../src/gui/unregisterdialog.cpp:49 +#, c-format +msgid "Name: %s" +msgstr "பெயர்: %s" + +#: ../src/gui/updaterwindow.cpp:123 +msgid "Updating..." +msgstr "புதுப்பித்தல் ..." + +#: ../src/gui/updaterwindow.cpp:138 +msgid "Connecting..." +msgstr "இணைத்தல் ..." + +#: ../src/gui/updaterwindow.cpp:141 +msgid "Play" +msgstr "விளையாடுங்கள்" + +#: ../src/gui/updaterwindow.cpp:408 +msgid "##1 The update process is incomplete." +msgstr "## 1 புதுப்பிப்பு செயல்முறை முழுமையடையாது." + +#: ../src/gui/updaterwindow.cpp:410 +msgid "##1 It is strongly recommended that" +msgstr "## 1 இது கடுமையாக பரிந்துரைக்கப்படுகிறது" + +#: ../src/gui/updaterwindow.cpp:412 +msgid "##1 you try again later." +msgstr "## 1 நீங்கள் பின்னர் மீண்டும் முயற்சிக்கிறீர்கள்." + +#: ../src/gui/updaterwindow.cpp:502 +msgid "Completed" +msgstr "முடிந்தது" + +#: ../src/gui/widgets/channeltab.cpp:48 +msgid "/users > Lists the users in the current channel" +msgstr "/பயனர்கள்> தற்போதைய சேனலில் பயனர்களை பட்டியலிடுகிறது" + +#: ../src/gui/widgets/channeltab.cpp:49 +msgid "/topic > Set the topic of the current channel" +msgstr "/தலைப்பு> தற்போதைய சேனலின் தலைப்பை அமைக்கவும்" + +#: ../src/gui/widgets/channeltab.cpp:50 +msgid "/quit > Leave a channel" +msgstr "/வெளியேறு> ஒரு சேனலை விட்டு விடுங்கள்" + +#: ../src/gui/widgets/channeltab.cpp:51 +msgid "/op > Make a user a channel operator" +msgstr "/op> ஒரு பயனரை சேனல் ஆபரேட்டராக மாற்றவும்" + +#: ../src/gui/widgets/channeltab.cpp:52 +msgid "/kick > Kick a user from the channel" +msgstr "/கிக்> சேனலில் இருந்து ஒரு பயனரை உதைக்கவும்" + +#: ../src/gui/widgets/channeltab.cpp:62 +msgid "Command: /users" +msgstr "கட்டளை: /பயனர்கள்" + +#: ../src/gui/widgets/channeltab.cpp:63 +msgid "This command shows the users in this channel." +msgstr "இந்த கட்டளை இந்த சேனலில் பயனர்களைக் காட்டுகிறது." + +#: ../src/gui/widgets/channeltab.cpp:67 +msgid "Command: /topic <message>" +msgstr "கட்டளை: /தலைப்பு <செய்தி>" + +#: ../src/gui/widgets/channeltab.cpp:68 +msgid "This command sets the topic to <message>." +msgstr "இந்த கட்டளை தலைப்பை <செய்தி> ஆக அமைக்கிறது." + +#: ../src/gui/widgets/channeltab.cpp:72 +msgid "Command: /quit" +msgstr "கட்டளை: /வெளியேறு" + +#: ../src/gui/widgets/channeltab.cpp:73 +msgid "This command leaves the current channel." +msgstr "இந்த கட்டளை தற்போதைய சேனலை விட்டு வெளியேறுகிறது." + +#: ../src/gui/widgets/channeltab.cpp:74 +msgid "If you're the last person in the channel, it will be deleted." +msgstr "நீங்கள் சேனலில் கடைசி நபராக இருந்தால், அது நீக்கப்படும்." + +#: ../src/gui/widgets/channeltab.cpp:79 +msgid "Command: /op <nick>" +msgstr "கட்டளை: /OP <நிக்>" + +#: ../src/gui/widgets/channeltab.cpp:80 +msgid "This command makes <nick> a channel operator." +msgstr "இந்த கட்டளை <நிக்> ஒரு சேனல் ஆபரேட்டரை உருவாக்குகிறது." + +#: ../src/gui/widgets/channeltab.cpp:83 +msgid "Channel operators can kick and op other users from the channel." +msgstr "சேனல் ஆபரேட்டர்கள் சேனலில் இருந்து பிற பயனர்களை உதைக்கலாம்." + +#: ../src/gui/widgets/channeltab.cpp:88 +msgid "Command: /kick <nick>" +msgstr "கட்டளை: /கிக் <நிக்>" + +#: ../src/gui/widgets/channeltab.cpp:89 +msgid "This command makes <nick> leave the channel." +msgstr "இந்த கட்டளை <நிக்> சேனலை விட்டு வெளியேறுகிறது." + +#: ../src/gui/widgets/channeltab.cpp:114 +msgid "Need a user to op!" +msgstr "OP க்கு ஒரு பயனர் தேவை!" + +#: ../src/gui/widgets/channeltab.cpp:121 +msgid "Need a user to kick!" +msgstr "உதைக்க ஒரு பயனர் தேவை!" + +#: ../src/gui/widgets/chattab.cpp:154 +msgid "Global announcement:" +msgstr "உலகளாவிய அறிவிப்பு:" + +#: ../src/gui/widgets/chattab.cpp:160 +#, c-format +msgid "Global announcement from %s:" +msgstr "%s இலிருந்து உலகளாவிய அறிவிப்பு:" + +#: ../src/gui/widgets/chattab.cpp:175 +msgid "Server:" +msgstr "சேவையகம்:" + +#: ../src/gui/widgets/chattab.cpp:186 +#, c-format +msgid "%s whispers: %s" +msgstr "%s கிசுகிசுக்கள்: %s" + +#: ../src/gui/widgets/itemlinkhandler.cpp:63 +msgid "Open URL?" +msgstr "திறந்த URL?" + +#: ../src/gui/widgets/itemlinkhandler.cpp:66 +#: ../src/gui/widgets/itemlinkhandler.cpp:95 +msgid "Open URL Failed" +msgstr "திறந்த முகவரி தோல்வியுற்றது" + +#: ../src/gui/widgets/itemlinkhandler.cpp:67 +msgid "Opening of URLs requires SDL 2.0.14." +msgstr "முகவரி களின் திறப்புக்கு SDL 2.0.14 தேவைப்படுகிறது." + +#: ../src/gui/widgets/whispertab.cpp:52 +msgid "Cannot send empty chat!" +msgstr "வெற்று அரட்டையை அனுப்ப முடியாது!" + +#: ../src/gui/widgets/whispertab.cpp:71 +msgid "/ignore > Ignore the other player" +msgstr "/புறக்கணிக்கவும்> மற்ற வீரரை புறக்கணிக்கவும்" + +#: ../src/gui/widgets/whispertab.cpp:72 +msgid "/unignore > Stop ignoring the other player" +msgstr "/unignore> மற்ற வீரரை புறக்கணிப்பதை நிறுத்துங்கள்" + +#: ../src/gui/widgets/whispertab.cpp:73 +msgid "/close > Close the whisper tab" +msgstr "/மூடு> விச்பர் தாவலை மூடு" + +#: ../src/gui/widgets/whispertab.cpp:83 +msgid "Command: /close" +msgstr "கட்டளை: /மூடு" + +#: ../src/gui/widgets/whispertab.cpp:84 +msgid "This command closes the current whisper tab." +msgstr "இந்த கட்டளை தற்போதைய விச்பர் தாவலை மூடுகிறது." + +#: ../src/gui/widgets/whispertab.cpp:88 +msgid "Command: /ignore" +msgstr "கட்டளை: /புறக்கணிக்கவும்" + +#: ../src/gui/widgets/whispertab.cpp:89 +msgid "This command ignores the other player regardless of current relations." +msgstr "" +"தற்போதைய உறவுகளைப் பொருட்படுத்தாமல் இந்த கட்டளை மற்ற வீரரை புறக்கணிக்கிறது." + +#: ../src/gui/widgets/whispertab.cpp:95 +msgid "This command stops ignoring the other player if they are being ignored." +msgstr "இந்த கட்டளை மற்ற வீரர்களை புறக்கணித்தால் புறக்கணிப்பதை நிறுத்துகிறது." + +#: ../src/gui/windowmenu.cpp:53 +msgid "Status" +msgstr "நிலை" + +#: ../src/gui/windowmenu.cpp:69 +msgid "Shortcuts" +msgstr "குறுக்குவழிகள்" + +#: ../src/gui/worldselectdialog.cpp:68 +msgid "Select World" +msgstr "உலகத்தைத் தேர்ந்தெடுக்கவும்" + +#: ../src/gui/worldselectdialog.cpp:73 +msgid "Change Login" +msgstr "உள்நுழைவை மாற்றவும்" + +#: ../src/gui/worldselectdialog.cpp:74 +msgid "Choose World" +msgstr "உலகத்தைத் தேர்வுசெய்க" + +#: ../src/keyboardconfig.cpp:42 +msgid "Move Up" +msgstr "மேலே செல்லுங்கள்" + +#: ../src/keyboardconfig.cpp:43 +msgid "Move Down" +msgstr "கீழே செல்லுங்கள்" + +#: ../src/keyboardconfig.cpp:44 +msgid "Move Left" +msgstr "இடதுபுறம் நகர்த்தவும்" + +#: ../src/keyboardconfig.cpp:45 +msgid "Move Right" +msgstr "வலதுபுறம் நகர்த்தவும்" + +#: ../src/keyboardconfig.cpp:46 ../src/net/tmwa/generalhandler.cpp:236 +msgid "Attack" +msgstr "தாக்குதல்" + +#: ../src/keyboardconfig.cpp:47 +msgid "Target & Attack" +msgstr "இலக்கு மற்றும் தாக்குதல்" + +#: ../src/keyboardconfig.cpp:48 +msgid "Smilie" +msgstr "புன்னகை" + +#: ../src/keyboardconfig.cpp:49 +msgid "Talk" +msgstr "பேச்சு" + +#: ../src/keyboardconfig.cpp:50 +msgid "Stop Attack" +msgstr "தாக்குதலை நிறுத்துங்கள்" + +#: ../src/keyboardconfig.cpp:51 +msgid "Target Monster" +msgstr "இலக்கு மான்ச்டர்" + +#: ../src/keyboardconfig.cpp:52 +msgid "Target NPC" +msgstr "இலக்கு NPC" + +#: ../src/keyboardconfig.cpp:53 +msgid "Target Player" +msgstr "இலக்கு வீரர்" + +#: ../src/keyboardconfig.cpp:54 +msgid "Pickup" +msgstr "இடும்" + +#: ../src/keyboardconfig.cpp:55 +msgid "Hide Windows" +msgstr "விண்டோசை மறைக்கவும்" + +#: ../src/keyboardconfig.cpp:56 +msgid "Sit" +msgstr "உட்கார்" + +#: ../src/keyboardconfig.cpp:57 +msgid "Screenshot" +msgstr "திரைக்காட்சி" + +#: ../src/keyboardconfig.cpp:58 +msgid "Enable/Disable Trading" +msgstr "வர்த்தகத்தை இயக்கவும்/முடக்கவும்" + +#: ../src/keyboardconfig.cpp:59 ../src/keyboardconfig.cpp:60 +#: ../src/keyboardconfig.cpp:61 ../src/keyboardconfig.cpp:62 +#: ../src/keyboardconfig.cpp:63 ../src/keyboardconfig.cpp:64 +#: ../src/keyboardconfig.cpp:65 ../src/keyboardconfig.cpp:66 +#: ../src/keyboardconfig.cpp:67 ../src/keyboardconfig.cpp:68 +#: ../src/keyboardconfig.cpp:69 ../src/keyboardconfig.cpp:70 +#, c-format +msgid "Item Shortcut %d" +msgstr "பொருள் குறுக்குவழி %d" + +#: ../src/keyboardconfig.cpp:71 +msgid "Help Window" +msgstr "உதவி சாளரம்" + +#: ../src/keyboardconfig.cpp:72 +msgid "Status Window" +msgstr "நிலை சாளரம்" + +#: ../src/keyboardconfig.cpp:73 +msgid "Inventory Window" +msgstr "சரக்கு சாளரம்" + +#: ../src/keyboardconfig.cpp:74 +msgid "Equipment Window" +msgstr "உபகரணங்கள் சாளரம்" + +#: ../src/keyboardconfig.cpp:75 +msgid "Skill Window" +msgstr "திறன் சாளரம்" + +#: ../src/keyboardconfig.cpp:76 +msgid "Minimap Window" +msgstr "மினிமாப் சாளரம்" + +#: ../src/keyboardconfig.cpp:77 +msgid "Chat Window" +msgstr "அரட்டை சாளரம்" + +#: ../src/keyboardconfig.cpp:78 +msgid "Item Shortcut Window" +msgstr "பொருள் குறுக்குவழி சாளரம்" + +#: ../src/keyboardconfig.cpp:79 +msgid "Setup Window" +msgstr "அமைவு சாளரம்" + +#: ../src/keyboardconfig.cpp:80 +msgid "Debug Window" +msgstr "பிழைத்திருத்த சாளரம்" + +#: ../src/keyboardconfig.cpp:81 +msgid "Social Window" +msgstr "சமூக சாளரம்" + +#: ../src/keyboardconfig.cpp:82 +msgid "Emote Shortcut Window" +msgstr "குறுக்குவழி சாளரத்தை வெளிப்படுத்துகிறது" + +#: ../src/keyboardconfig.cpp:83 +msgid "Outfits Window" +msgstr "ஆடைகள் சாளரம்" + +#: ../src/keyboardconfig.cpp:84 +msgid "Wear Outfit" +msgstr "ஆடை அணியுங்கள்" + +#: ../src/keyboardconfig.cpp:85 +msgid "Copy Outfit" +msgstr "அலங்காரத்தை நகலெடுக்கவும்" + +#: ../src/keyboardconfig.cpp:86 ../src/keyboardconfig.cpp:87 +#: ../src/keyboardconfig.cpp:88 ../src/keyboardconfig.cpp:89 +#: ../src/keyboardconfig.cpp:90 ../src/keyboardconfig.cpp:91 +#: ../src/keyboardconfig.cpp:92 ../src/keyboardconfig.cpp:93 +#: ../src/keyboardconfig.cpp:94 ../src/keyboardconfig.cpp:95 +#: ../src/keyboardconfig.cpp:96 ../src/keyboardconfig.cpp:97 +#, c-format +msgid "Emote Shortcut %d" +msgstr "எமோட் குறுக்குவழி %d" + +#: ../src/keyboardconfig.cpp:98 +msgid "Toggle Chat" +msgstr "அரட்டையை மாற்றவும்" + +#: ../src/keyboardconfig.cpp:99 +msgid "Scroll Chat Up" +msgstr "அரட்டை உருட்டவும்" + +#: ../src/keyboardconfig.cpp:100 +msgid "Scroll Chat Down" +msgstr "உருட்டல் அரட்டை கீழே" + +#: ../src/keyboardconfig.cpp:101 +msgid "Previous Chat Tab" +msgstr "முந்தைய அரட்டை தாவல்" + +#: ../src/keyboardconfig.cpp:102 +msgid "Next Chat Tab" +msgstr "அடுத்த அரட்டை தாவல்" + +#: ../src/keyboardconfig.cpp:103 +msgid "Select OK" +msgstr "சரி என்பதைத் தேர்ந்தெடுக்கவும்" + +#: ../src/keyboardconfig.cpp:105 +msgid "Ignore input 1" +msgstr "உள்ளீடு 1 ஐ புறக்கணிக்கவும்" + +#: ../src/keyboardconfig.cpp:106 +msgid "Ignore input 2" +msgstr "உள்ளீடு 2 ஐ புறக்கணிக்கவும்" + +#: ../src/keyboardconfig.cpp:185 +#, c-format +msgid "" +"Conflict \"%s\" and \"%s\" keys. Resolve them, or gameplay may result in " +"strange behaviour." +msgstr "" +"மோதல் \"%s\" மற்றும் \"%s\" விசைகள். அவற்றைத் தீர்க்கவும், அல்லது விளையாட்டு விசித்திரமான " +"நடத்தைக்கு வழிவகுக்கும்." + +#: ../src/localplayer.cpp:864 +msgid "Tried to pick up nonexistent item." +msgstr "இல்லாத உருப்படியை எடுக்க முயற்சித்தேன்." + +#: ../src/localplayer.cpp:865 +msgid "Item is too heavy." +msgstr "உருப்படி மிகவும் கனமானது." + +#: ../src/localplayer.cpp:866 +msgid "Item is too far away" +msgstr "உருப்படி மிகவும் தொலைவில் உள்ளது" + +#: ../src/localplayer.cpp:867 +msgid "Inventory is full." +msgstr "சரக்கு நிரம்பியுள்ளது." + +#: ../src/localplayer.cpp:868 +msgid "Stack is too big." +msgstr "அடுக்கு மிகப் பெரியது." + +#: ../src/localplayer.cpp:870 +msgid "Item belongs to someone else." +msgstr "உருப்படி வேறொருவருக்கு சொந்தமானது." + +#: ../src/localplayer.cpp:871 +msgid "Unknown problem picking up item." +msgstr "அறியப்படாத சிக்கல் உருப்படியை எடுப்பதில்." + +#: ../src/localplayer.cpp:889 +#, c-format +msgid "You picked up %d [@@%d|%s@@]." +msgid_plural "You picked up %d [@@%d|%s@@]." +msgstr[0] "நீங்கள்%d ஐ எடுத்தீர்கள் [@@%d |%s @@]." +msgstr[1] "நீங்கள்%d ஐ எடுத்தீர்கள் [@@%d |%s @@]." + +#: ../src/localplayer.cpp:1023 +msgid "Away" +msgstr "தொலைவில்" + +#: ../src/main.cpp:49 +msgid "mana [options] [mana-file]" +msgstr "மனா [விருப்பங்கள்] [மன-கோப்பு]" + +#: ../src/main.cpp:50 +msgid "[mana-file] : The mana file is an XML file (.mana)" +msgstr "[மனா-கோப்பு]: மனா கோப்பு ஒரு எக்ச்எம்எல் கோப்பு (. மேனா)" + +#: ../src/main.cpp:51 +msgid " used to set custom parameters" +msgstr " தனிப்பயன் அளவுருக்களை அமைக்கப் பயன்படுகிறது" + +#: ../src/main.cpp:52 +msgid " to the mana client." +msgstr " மன வாடிக்கையாளருக்கு." + +#: ../src/main.cpp:54 +msgid "Options:" +msgstr "விருப்பங்கள்:" + +#: ../src/main.cpp:55 +msgid " -v --version : Display the version" +msgstr " -v --version: பதிப்பைக் காண்பி" + +#: ../src/main.cpp:56 +msgid " -h --help : Display this help" +msgstr " -h -உதவி: இந்த உதவியைக் காண்பி" + +#: ../src/main.cpp:57 +msgid " -C --config-dir : Configuration directory to use" +msgstr " -C--config-dir: பயன்படுத்த உள்ளமைவு அடைவு" + +#: ../src/main.cpp:58 +msgid " -U --username : Login with this username" +msgstr " -U --username: இந்த பயனர்பெயருடன் உள்நுழைக" + +#: ../src/main.cpp:59 +msgid " -P --password : Login with this password" +msgstr " -P - -பாச்வேர்ட்: இந்த கடவுச்சொல்லுடன் உள்நுழைக" + +#: ../src/main.cpp:60 +msgid " -c --character : Login with this character" +msgstr " -c --caracter: இந்த எழுத்துடன் உள்நுழைக" + +#: ../src/main.cpp:61 +msgid " -s --server : Login server name or IP" +msgstr " -S -சேவையகம்: உள்நுழைவு சேவையக பெயர் அல்லது ஐபி" + +#: ../src/main.cpp:62 +msgid " -p --port : Login server port" +msgstr " -p -போர்ட்: உள்நுழைவு சேவையக துறைமுகம்" + +#: ../src/main.cpp:63 +msgid " -y --server-type : Login server type" +msgstr " -y--சேவையக வகை: உள்நுழைவு சேவையக வகை" + +#: ../src/main.cpp:64 +msgid " --update-host : Use this update host" +msgstr " -அப்டேட்-ஓச்ட்: இந்த புதுப்பிப்பு ஓச்டைப் பயன்படுத்தவும்" + +#: ../src/main.cpp:65 +msgid " -D --default : Choose default character server and character" +msgstr "" +" -D - -default: இயல்புநிலை எழுத்து சேவையகம் மற்றும் எழுத்தைத் தேர்வுசெய்க" + +#: ../src/main.cpp:67 +msgid " -u --skip-update : Skip the update downloads" +msgstr " -U--ச்கிப்-அப்-அப்டேட்: புதுப்பிப்பு பதிவிறக்கங்களைத் தவிர்க்கவும்" + +#: ../src/main.cpp:68 +msgid " -d --data : Directory to load game data from" +msgstr " -d - -data: விளையாட்டு தரவை ஏற்றுவதற்கான அடைவு" + +#: ../src/main.cpp:69 +msgid " --localdata-dir : Directory to use as local data directory" +msgstr " --லோகல்டேட்டா-டி.ஐ.ஆர்: உள்ளக தரவு கோப்பகமாக பயன்படுத்த கோப்பகம்" + +#: ../src/main.cpp:70 +msgid " --chat-log-dir : Chat log dir to use" +msgstr " --chat-log-dir: பயன்படுத்த அரட்டை பதிவு" + +#: ../src/main.cpp:71 +msgid " --screenshot-dir : Directory to store screenshots" +msgstr " -ச்க்ரீன்சாட்-டி.ஐ.ஆர்: திரை சாட்களை சேமிக்கும் அடைவு" + +#: ../src/main.cpp:73 +msgid " --no-opengl : Disable OpenGL for this session" +msgstr " -no-opengl: இந்த அமர்வுக்கு Opengl ஐ முடக்கு" + +#: ../src/main.cpp:173 +msgid "Invalid server type, expected one of: tmwathena, manaserv" +msgstr "தவறான சேவையக வகை, அவற்றில் ஒன்று: tmwathena, Manaserv" + +#: ../src/net/manaserv/beinghandler.cpp:278 +#: ../src/net/tmwa/playerhandler.cpp:94 +msgid "You are dead." +msgstr "நீங்கள் இறந்துவிட்டீர்கள்." + +#: ../src/net/manaserv/beinghandler.cpp:279 +#: ../src/net/tmwa/playerhandler.cpp:95 +msgid "We regret to inform you that your character was killed in battle." +msgstr "" +"உங்கள் கதாபாத்திரம் போரில் கொல்லப்பட்டது என்பதை உங்களுக்குத் தெரிவிக்க வருத்தப்படுகிறோம்." + +#: ../src/net/manaserv/beinghandler.cpp:281 +#: ../src/net/tmwa/playerhandler.cpp:97 +msgid "You are not that alive anymore." +msgstr "நீங்கள் இனி உயிருடன் இல்லை." + +#: ../src/net/manaserv/beinghandler.cpp:282 +#: ../src/net/tmwa/playerhandler.cpp:98 +msgid "The cold hands of the grim reaper are grabbing for your soul." +msgstr "கிரிம் ரீப்பரின் குளிர்ந்த கைகள் உங்கள் ஆத்மாவைப் பிடிக்கும்." + +#: ../src/net/manaserv/beinghandler.cpp:283 +#: ../src/net/tmwa/playerhandler.cpp:99 +msgid "Game Over!" +msgstr "விளையாட்டு ஓவர்!" + +#: ../src/net/manaserv/beinghandler.cpp:284 +#: ../src/net/tmwa/playerhandler.cpp:101 +msgid "" +"No, kids. Your character did not really die. It... err... went to a better " +"place." +msgstr "" +"இல்லை, குழந்தைகள். உங்கள் பாத்திரம் உண்மையில் இறக்கவில்லை. அது ... பிழை ... ஒரு சிறந்த " +"இடத்திற்குச் சென்றது." + +#: ../src/net/manaserv/beinghandler.cpp:286 +#: ../src/net/tmwa/playerhandler.cpp:103 +msgid "" +"Your plan of breaking your enemies weapon by bashing it with your throat " +"failed." +msgstr "" +"உங்கள் எதிரிகளின் ஆயுதத்தை உங்கள் தொண்டையால் அடித்ததன் மூலம் அதை உடைக்கும் திட்டம் " +"தோல்வியடைந்தது." + +#: ../src/net/manaserv/beinghandler.cpp:288 +#: ../src/net/tmwa/playerhandler.cpp:105 +msgid "I guess this did not run too well." +msgstr "இது நன்றாக இயங்கவில்லை என்று நினைக்கிறேன்." + +#: ../src/net/manaserv/beinghandler.cpp:289 +#: ../src/net/tmwa/playerhandler.cpp:107 +msgid "Do you want your possessions identified?" +msgstr "உங்கள் உடைமைகளை அடையாளம் காண விரும்புகிறீர்களா?" + +#: ../src/net/manaserv/beinghandler.cpp:290 +#: ../src/net/tmwa/playerhandler.cpp:109 +msgid "Sadly, no trace of you was ever found..." +msgstr "துரதிர்ச்டவசமாக, உங்கள் எந்த தடயமும் இதுவரை காணப்படவில்லை ..." + +#: ../src/net/manaserv/beinghandler.cpp:291 +#: ../src/net/tmwa/playerhandler.cpp:111 +msgid "Annihilated." +msgstr "நிர்மூலமாக்கப்பட்டது." + +#: ../src/net/manaserv/beinghandler.cpp:292 +#: ../src/net/tmwa/playerhandler.cpp:113 +msgid "Looks like you got your head handed to you." +msgstr "உங்கள் தலையை உங்களிடம் ஒப்படைத்தது போல் தெரிகிறது." + +#: ../src/net/manaserv/beinghandler.cpp:293 +#: ../src/net/tmwa/playerhandler.cpp:115 +msgid "" +"You screwed up again, dump your body down the tubes and get you another one." +msgstr "" +"நீங்கள் மீண்டும் திருகிவிட்டீர்கள், உங்கள் உடலை குழாய்களின் கீழே கொட்டிவிட்டு, உங்களுக்கு " +"இன்னொன்றைப் பெறுங்கள்." + +#: ../src/net/manaserv/beinghandler.cpp:298 +msgid "Press OK to respawn." +msgstr "ரெச்பானுக்கு சரி என்பதை அழுத்தவும்." + +#: ../src/net/manaserv/beinghandler.cpp:299 +msgid "You Died" +msgstr "நீங்கள் இறந்துவிட்டீர்கள்" + +#: ../src/net/manaserv/charhandler.cpp:139 +#: ../src/net/manaserv/charhandler.cpp:220 +msgid "Not logged in." +msgstr "உள்நுழையவில்லை." + +#: ../src/net/manaserv/charhandler.cpp:142 +msgid "No empty slot." +msgstr "வெற்று ச்லாட் இல்லை." + +#: ../src/net/manaserv/charhandler.cpp:145 +msgid "Invalid name." +msgstr "தவறான பெயர்." + +#: ../src/net/manaserv/charhandler.cpp:148 +msgid "Character's name already exists." +msgstr "கதாபாத்திரத்தின் பெயர் ஏற்கனவே உள்ளது." + +#: ../src/net/manaserv/charhandler.cpp:151 +msgid "Invalid hairstyle." +msgstr "தவறான சிகை ஒப்பனை." + +#: ../src/net/manaserv/charhandler.cpp:154 +msgid "Invalid hair color." +msgstr "தவறான முடி நிறம்." + +#: ../src/net/manaserv/charhandler.cpp:157 +msgid "Invalid gender." +msgstr "தவறான பாலினம்." + +#: ../src/net/manaserv/charhandler.cpp:160 +msgid "Character's stats are too high." +msgstr "எழுத்து புள்ளிவிவரங்கள் மிக அதிகம்." + +#: ../src/net/manaserv/charhandler.cpp:163 +msgid "Character's stats are too low." +msgstr "எழுத்து புள்ளிவிவரங்கள் மிகக் குறைவு." + +#: ../src/net/manaserv/charhandler.cpp:166 +#, c-format +msgid "At least one stat is out of the permitted range: (%u - %u)." +msgstr "அனுமதிக்கப்பட்ட வரம்பில் குறைந்தது ஒரு STAT இல்லை: ( %u - %u)." + +#: ../src/net/manaserv/charhandler.cpp:172 +msgid "Invalid slot number." +msgstr "தவறான ச்லாட் எண்." + +#: ../src/net/manaserv/charhandler.cpp:175 +#: ../src/net/manaserv/loginhandler.cpp:101 +#: ../src/net/manaserv/loginhandler.cpp:132 +#: ../src/net/manaserv/loginhandler.cpp:166 +#: ../src/net/manaserv/loginhandler.cpp:290 +#: ../src/net/manaserv/loginhandler.cpp:327 ../src/net/tmwa/loginhandler.cpp:98 +#: ../src/net/tmwa/loginhandler.cpp:195 +msgid "Unknown error." +msgstr "தெரியாத பிழை." + +#: ../src/net/manaserv/charhandler.cpp:211 +msgid "Player deleted." +msgstr "பிளேயர் நீக்கப்பட்டது." + +#: ../src/net/manaserv/charhandler.cpp:223 +msgid "Selection out of range." +msgstr "வரம்பிலிருந்து தேர்வு." + +#: ../src/net/manaserv/charhandler.cpp:226 +#, c-format +msgid "Unknown error (%d)." +msgstr "தெரியாத பிழை (%d)." + +#: ../src/net/manaserv/charhandler.cpp:265 +msgid "No gameservers are available." +msgstr "கேம்சர்வர்கள் எதுவும் கிடைக்கவில்லை." + +#: ../src/net/manaserv/charhandler.cpp:268 +msgid "Invalid character slot selected." +msgstr "தவறான எழுத்து ச்லாட் தேர்ந்தெடுக்கப்பட்டது." + +#: ../src/net/manaserv/charhandler.cpp:271 +#, c-format +msgid "Unhandled character select error message %i." +msgstr "தடையற்ற எழுத்து தேர்ந்தெடுக்கப்பட்ட பிழை செய்தி %i." + +#: ../src/net/manaserv/chathandler.cpp:190 +#: ../src/net/manaserv/chathandler.cpp:324 +#: ../src/net/manaserv/guildhandler.cpp:285 +#, c-format +msgid "Topic: %s" +msgstr "தலைப்பு: %s" + +#: ../src/net/manaserv/chathandler.cpp:194 +#: ../src/net/manaserv/chathandler.cpp:285 +msgid "Players in this channel:" +msgstr "இந்த சேனலில் வீரர்கள்:" + +#: ../src/net/manaserv/chathandler.cpp:211 +msgid "Error joining channel." +msgstr "சேனலில் சேருவதில் பிழை." + +#: ../src/net/manaserv/chathandler.cpp:217 +msgid "Listing channels." +msgstr "சேனல்களை பட்டியலிடுதல்." + +#: ../src/net/manaserv/chathandler.cpp:229 +msgid "End of channel list." +msgstr "சேனல் பட்டியலின் முடிவு." + +#: ../src/net/manaserv/chathandler.cpp:314 +#, c-format +msgid "%s entered the channel." +msgstr "%s சேனலில் நுழைந்தன." + +#: ../src/net/manaserv/chathandler.cpp:319 +#, c-format +msgid "%s left the channel." +msgstr "%s சேனலை விட்டு வெளியேறின." + +#: ../src/net/manaserv/chathandler.cpp:335 +#, c-format +msgid "%s has set mode %s on user %s." +msgstr "%s பயன்முறை %s பயனர்மீது %s அமைத்துள்ளார்." + +#: ../src/net/manaserv/chathandler.cpp:345 +#, c-format +msgid "%s has kicked %s." +msgstr "%s %s உதைத்துள்ளன." + +#: ../src/net/manaserv/chathandler.cpp:350 +msgid "Unknown channel event." +msgstr "அறியப்படாத சேனல் நிகழ்வு." + +#: ../src/net/manaserv/guildhandler.cpp:80 +msgid "Guild created." +msgstr "கில்ட் உருவாக்கப்பட்டது." + +#: ../src/net/manaserv/guildhandler.cpp:85 +msgid "Error creating guild." +msgstr "கில்ட் உருவாக்கும் பிழை." + +#: ../src/net/manaserv/guildhandler.cpp:96 +msgid "Invite sent." +msgstr "அனுப்பப்பட்டதை அழைக்கவும்." + +#: ../src/net/manaserv/guildhandler.cpp:100 +msgid "Invited player is already in that guild." +msgstr "அழைக்கப்பட்ட வீரர் ஏற்கனவே அந்த கில்டில் இருக்கிறார்." + +#: ../src/net/manaserv/guildhandler.cpp:104 +msgid "Invited player can't join another guild." +msgstr "அழைக்கப்பட்ட வீரர் மற்றொரு கில்டில் சேர முடியாது." + +#: ../src/net/manaserv/guildhandler.cpp:108 +msgid "Invite failed." +msgstr "அழைப்பு தோல்வியடைந்தது." + +#: ../src/net/manaserv/guildhandler.cpp:215 +msgid "Member was promoted successfully." +msgstr "உறுப்பினர் வெற்றிகரமாக பதவி உயர்வு பெற்றார்." + +#: ../src/net/manaserv/guildhandler.cpp:220 +msgid "Failed to promote member." +msgstr "உறுப்பினரை ஊக்குவிப்பதில் தோல்வி." + +#: ../src/net/manaserv/guildhandler.cpp:259 +#, c-format +msgid "Player %s kicked you out of guild %s." +msgstr "வீரர்கள் %s உங்களைக் கில்ட் %s இலிருந்து உதைத்தனர்." + +#: ../src/net/manaserv/loginhandler.cpp:92 +msgid "Wrong magic_token." +msgstr "தவறான மேசிக்_டோகன்." + +#: ../src/net/manaserv/loginhandler.cpp:95 +#: ../src/net/manaserv/loginhandler.cpp:280 +msgid "Already logged in." +msgstr "ஏற்கனவே உள்நுழைந்துள்ளது." + +#: ../src/net/manaserv/loginhandler.cpp:98 +msgid "Account banned." +msgstr "கணக்கு தடைசெய்யப்பட்டது." + +#: ../src/net/manaserv/loginhandler.cpp:123 +msgid "New password incorrect." +msgstr "புதிய கடவுச்சொல் தவறானது." + +#: ../src/net/manaserv/loginhandler.cpp:126 ../src/net/tmwa/loginhandler.cpp:92 +msgid "Old password incorrect." +msgstr "பழைய கடவுச்சொல் தவறானது." + +#: ../src/net/manaserv/loginhandler.cpp:129 +#: ../src/net/manaserv/loginhandler.cpp:160 +msgid "Account not connected. Please login first." +msgstr "கணக்கு இணைக்கப்படவில்லை. முதலில் உள்நுழைக." + +#: ../src/net/manaserv/loginhandler.cpp:154 +msgid "New email address incorrect." +msgstr "புதிய மின்னஞ்சல் முகவரி தவறானது." + +#: ../src/net/manaserv/loginhandler.cpp:157 +msgid "Old email address incorrect." +msgstr "பழைய மின்னஞ்சல் முகவரி தவறானது." + +#: ../src/net/manaserv/loginhandler.cpp:163 +msgid "The new email address already exists." +msgstr "புதிய மின்னஞ்சல் முகவரி ஏற்கனவே உள்ளது." + +#: ../src/net/manaserv/loginhandler.cpp:244 +msgid "" +"Client registration is not allowed. Please contact server administration." +msgstr "" +"வாடிக்கையாளர் பதிவு அனுமதிக்கப்படவில்லை. சேவையக நிர்வாகத்தை தொடர்பு கொள்ளவும்." + +#: ../src/net/manaserv/loginhandler.cpp:274 +#: ../src/net/manaserv/loginhandler.cpp:311 +msgid "Client version is too old." +msgstr "கிளையன்ட் பதிப்பு மிகவும் பழையது." + +#: ../src/net/manaserv/loginhandler.cpp:277 +msgid "Wrong username or password." +msgstr "தவறான பயனர்பெயர் அல்லது கடவுச்சொல்." + +#: ../src/net/manaserv/loginhandler.cpp:283 +msgid "Account banned" +msgstr "கணக்கு தடைசெய்யப்பட்டது" + +#: ../src/net/manaserv/loginhandler.cpp:286 +msgid "Login attempt too soon after previous attempt." +msgstr "முந்தைய முயற்சியின் பின்னர் மிக விரைவில் உள்நுழைவு முயற்சி." + +#: ../src/net/manaserv/loginhandler.cpp:314 +msgid "Wrong username, password or email address." +msgstr "தவறான பயனர்பெயர், கடவுச்சொல் அல்லது மின்னஞ்சல் முகவரி." + +#: ../src/net/manaserv/loginhandler.cpp:317 +msgid "Username already exists." +msgstr "பயனர்பெயர் ஏற்கனவே உள்ளது." + +#: ../src/net/manaserv/loginhandler.cpp:320 +msgid "Email address already exists." +msgstr "மின்னஞ்சல் முகவரி ஏற்கனவே உள்ளது." + +#: ../src/net/manaserv/loginhandler.cpp:323 +msgid "You took too long with the captcha or your response was incorrect." +msgstr "" +"நீங்கள் கேப்ட்சாவுடன் அதிக நேரம் எடுத்தீர்கள் அல்லது உங்கள் பதில் தவறானது." + +#: ../src/net/manaserv/partyhandler.cpp:75 +#, c-format +msgid "" +"Party invite failed, because no player called %s is within the visual range." +msgstr "" +"கட்சி அழைப்பு தோல்வியடைந்தது, ஏனென்றால் %s என்று அழைக்கப்படும் எந்த வீரரும் காட்சி " +"வரம்பிற்குள் இல்லை." + +#: ../src/net/manaserv/partyhandler.cpp:98 +msgid "" +"Joining party failed, because the invitation has timed out on the server." +msgstr "" +"கட்சியில் சேருவது தோல்வியுற்றது, ஏனென்றால் அழைப்பிதழ் சேவையகத்தில் நேரம் முடிந்துவிட்டது." + +#: ../src/net/manaserv/partyhandler.cpp:102 +msgid "Joining party failed, because the inviter has left the game." +msgstr "" +"கட்சியில் சேருவது தோல்வியுற்றது, ஏனெனில் அழைப்பாளர் விளையாட்டை விட்டு வெளியேறினார்." + +#: ../src/net/manaserv/partyhandler.cpp:127 +#, c-format +msgid "%s joined the party." +msgstr "%s கட்சியில் சேர்ந்தார்." + +#: ../src/net/manaserv/partyhandler.cpp:129 +#, c-format +msgid "%s joined the party on invitation from %s." +msgstr "%s அழைப்பின் பேரில் %s கட்சியில் சேர்ந்தார்." + +#: ../src/net/manaserv/partyhandler.cpp:151 +#, c-format +msgid "%s rejected your invite." +msgstr "%s உங்கள் அழைப்பை நிராகரித்தன." + +#: ../src/net/manaserv/partyhandler.cpp:155 +msgid "" +"Party invitation rejected by server, because of too many invitations in a " +"short time." +msgstr "" +"கட்சி அழைப்பிதழ் சேவையகத்தால் நிராகரிக்கப்பட்டது, ஏனெனில் குறுகிய காலத்தில் பல " +"அழைப்பிதழ்கள்." + +#: ../src/net/manaserv/partyhandler.cpp:160 +#, c-format +msgid "%s is already in a party." +msgstr "%s ஏற்கனவே ஒரு கட்சியில் உள்ளன." + +#: ../src/net/manaserv/tradehandler.cpp:95 +msgid "Accepting incoming trade requests." +msgstr "உள்வரும் வர்த்தக கோரிக்கைகளை ஏற்றுக்கொள்வது." + +#: ../src/net/manaserv/tradehandler.cpp:97 +msgid "Ignoring incoming trade requests." +msgstr "உள்வரும் வர்த்தக கோரிக்கைகளை புறக்கணித்தல்." + +#: ../src/net/manaserv/tradehandler.cpp:115 +#: ../src/net/tmwa/tradehandler.cpp:109 +msgid "Request for Trade" +msgstr "வர்த்தகத்திற்கான கோரிக்கை" + +#: ../src/net/manaserv/tradehandler.cpp:116 +#: ../src/net/tmwa/tradehandler.cpp:110 +#, c-format +msgid "%s wants to trade with you, do you accept?" +msgstr "%s உங்களுடன் வணிகம் செய்ய விரும்புகின்றன, நீங்கள் ஏற்றுக்கொள்கிறீர்களா?" + +#: ../src/net/manaserv/tradehandler.cpp:134 +#, c-format +msgid "Trading with %s" +msgstr "%s உடன் வணிகம்" + +#: ../src/net/manaserv/tradehandler.cpp:148 +#: ../src/net/tmwa/tradehandler.cpp:231 +msgid "Trade canceled." +msgstr "வணிகம் ரத்து செய்யப்பட்டது." + +#: ../src/net/manaserv/tradehandler.cpp:155 +#: ../src/net/tmwa/tradehandler.cpp:238 +msgid "Trade completed." +msgstr "வணிகம் முடிந்தது." + +#: ../src/net/net.cpp:140 +msgid "Unknown Server Type! Exiting." +msgstr "தெரியாத சேவையக வகை! வெளியேறுதல்." + +#: ../src/net/net.cpp:165 +msgid "Server protocol unsupported" +msgstr "சேவையக நெறிமுறை ஆதரிக்கப்படவில்லை" + +#: ../src/net/tmwa/adminhandler.cpp:63 +msgid "Kick failed!" +msgstr "கிக் தோல்வியுற்றது!" + +#: ../src/net/tmwa/adminhandler.cpp:65 +msgid "Kick succeeded!" +msgstr "கிக் செய் பெற்றது!" + +#: ../src/net/tmwa/buysellhandler.cpp:108 +msgid "Nothing to sell." +msgstr "விற்க எதுவும் இல்லை." + +#: ../src/net/tmwa/buysellhandler.cpp:118 +msgid "Unable to buy." +msgstr "வாங்க முடியவில்லை." + +#: ../src/net/tmwa/buysellhandler.cpp:124 +msgid "Unable to sell." +msgstr "விற்க முடியவில்லை." + +#: ../src/net/tmwa/charserverhandler.cpp:105 +msgid "Access denied. Most likely, there are too many players on this server." +msgstr "" +"அணுகல் மறுக்கப்பட்டது. பெரும்பாலும், இந்த சேவையகத்தில் அதிகமான வீரர்கள் உள்ளனர்." + +#: ../src/net/tmwa/charserverhandler.cpp:109 +msgid "Cannot use this ID." +msgstr "இந்த ஐடியைப் பயன்படுத்த முடியாது." + +#: ../src/net/tmwa/charserverhandler.cpp:112 +msgid "Unknown char-server failure." +msgstr "அறியப்படாத கரி-சேவையக தோல்வி." + +#: ../src/net/tmwa/charserverhandler.cpp:136 +msgid "Failed to create character. Most likely the name is already taken." +msgstr "" +"தன்மையை உருவாக்கத் தவறிவிட்டது. பெரும்பாலும் பெயர் ஏற்கனவே எடுக்கப்பட்டுள்ளது." + +#: ../src/net/tmwa/charserverhandler.cpp:148 +msgid "Character deleted." +msgstr "எழுத்து நீக்கப்பட்டது." + +#: ../src/net/tmwa/charserverhandler.cpp:153 +msgid "Failed to delete character." +msgstr "தன்மையை நீக்குவதில் தோல்வி." + +#: ../src/net/tmwa/charserverhandler.cpp:283 +msgid "Strength:" +msgstr "வலிமை:" + +#: ../src/net/tmwa/charserverhandler.cpp:284 +msgid "Agility:" +msgstr "சுறுசுறுப்பு:" + +#: ../src/net/tmwa/charserverhandler.cpp:285 +msgid "Vitality:" +msgstr "உயிர்ச்சக்தி:" + +#: ../src/net/tmwa/charserverhandler.cpp:286 +msgid "Intelligence:" +msgstr "நுண்ணறிவு:" + +#: ../src/net/tmwa/charserverhandler.cpp:287 +msgid "Dexterity:" +msgstr "திறமை:" + +#: ../src/net/tmwa/charserverhandler.cpp:288 +msgid "Luck:" +msgstr "அதிர்ச்டம்:" + +#: ../src/net/tmwa/chathandler.cpp:90 +#, c-format +msgid "Whisper could not be sent, %s is offline." +msgstr "விச்பரை அனுப்ப முடியவில்லை, %s ஆஃப்லைனில் உள்ளன." + +#: ../src/net/tmwa/chathandler.cpp:99 +#, c-format +msgid "Whisper could not be sent, ignored by %s." +msgstr "விச்பரை அனுப்ப முடியவில்லை, %s ஆல் புறக்கணிக்கப்பட்டது." + +#: ../src/net/tmwa/chathandler.cpp:325 ../src/net/tmwa/chathandler.cpp:331 +#: ../src/net/tmwa/chathandler.cpp:336 ../src/net/tmwa/chathandler.cpp:341 +#: ../src/net/tmwa/chathandler.cpp:346 ../src/net/tmwa/chathandler.cpp:351 +#: ../src/net/tmwa/chathandler.cpp:356 ../src/net/tmwa/chathandler.cpp:361 +msgid "Channels are not supported!" +msgstr "சேனல்கள் ஆதரிக்கப்படவில்லை!" + +#: ../src/net/tmwa/gamehandler.cpp:89 +msgid "Game" +msgstr "விளையாட்டு" + +#: ../src/net/tmwa/gamehandler.cpp:89 +msgid "Request to quit denied!" +msgstr "விலகுவதற்கான கோரிக்கை மறுக்கப்பட்டது!" + +#: ../src/net/tmwa/generalhandler.cpp:99 +#, c-format +msgid "Strength %+d" +msgstr "வலிமை %+d" + +#: ../src/net/tmwa/generalhandler.cpp:100 +#, c-format +msgid "Agility %+d" +msgstr "சுறுசுறுப்பு %+d" + +#: ../src/net/tmwa/generalhandler.cpp:101 +#, c-format +msgid "Vitality %+d" +msgstr "உயிர்ச்சக்தி %+d" + +#: ../src/net/tmwa/generalhandler.cpp:102 +#, c-format +msgid "Intelligence %+d" +msgstr "நுண்ணறிவு %+d" + +#: ../src/net/tmwa/generalhandler.cpp:103 +#, c-format +msgid "Dexterity %+d" +msgstr "திறமை %+d" + +#: ../src/net/tmwa/generalhandler.cpp:104 +#, c-format +msgid "Luck %+d" +msgstr "அதிர்ச்டம் %+d" + +#: ../src/net/tmwa/generalhandler.cpp:130 +msgid "Authentication failed." +msgstr "ஏற்பு தோல்வியடைந்தது." + +#: ../src/net/tmwa/generalhandler.cpp:133 +msgid "No servers available." +msgstr "சேவையகங்கள் எதுவும் கிடைக்கவில்லை." + +#: ../src/net/tmwa/generalhandler.cpp:137 +msgid "Someone else is trying to use this account." +msgstr "வேறொருவர் இந்த கணக்கைப் பயன்படுத்த முயற்சிக்கிறார்." + +#: ../src/net/tmwa/generalhandler.cpp:140 +msgid "This account is already logged in." +msgstr "இந்த கணக்கு ஏற்கனவே உள்நுழைந்துள்ளது." + +#: ../src/net/tmwa/generalhandler.cpp:143 +msgid "Speed hack detected." +msgstr "வேக ஏக் கண்டறியப்பட்டது." + +#: ../src/net/tmwa/generalhandler.cpp:146 +msgid "Duplicated login." +msgstr "நகல் உள்நுழைவு." + +#: ../src/net/tmwa/generalhandler.cpp:149 +msgid "Unknown connection error." +msgstr "தெரியாத இணைப்பு பிழை." + +#: ../src/net/tmwa/generalhandler.cpp:207 +msgid "Got disconnected from server!" +msgstr "சேவையகத்திலிருந்து துண்டிக்கப்பட்டது!" + +#: ../src/net/tmwa/generalhandler.cpp:228 ../src/resources/attributes.cpp:159 +msgid "Strength" +msgstr "வலிமை" + +#: ../src/net/tmwa/generalhandler.cpp:229 ../src/resources/attributes.cpp:171 +msgid "Agility" +msgstr "சுறுசுறுப்பு" + +#: ../src/net/tmwa/generalhandler.cpp:230 ../src/resources/attributes.cpp:195 +msgid "Vitality" +msgstr "உயிர்ச்சக்தி" + +#: ../src/net/tmwa/generalhandler.cpp:231 ../src/resources/attributes.cpp:207 +msgid "Intelligence" +msgstr "நுண்ணறிவு" + +#: ../src/net/tmwa/generalhandler.cpp:233 ../src/resources/attributes.cpp:183 +msgid "Dexterity" +msgstr "திறமை" + +#: ../src/net/tmwa/generalhandler.cpp:234 +msgid "Luck" +msgstr "அதிர்ச்டம்" + +#: ../src/net/tmwa/generalhandler.cpp:237 +msgid "Defense" +msgstr "பாதுகாப்பு" + +#: ../src/net/tmwa/generalhandler.cpp:238 +msgid "M.Attack" +msgstr "M.attack" + +#: ../src/net/tmwa/generalhandler.cpp:239 +msgid "M.Defense" +msgstr "எம்" + +#: ../src/net/tmwa/generalhandler.cpp:243 +#, no-c-format +msgid "% Accuracy" +msgstr "% துல்லியம்" + +#: ../src/net/tmwa/generalhandler.cpp:245 +#, no-c-format +msgid "% Evade" +msgstr "% தவிர்க்கவும்" + +#: ../src/net/tmwa/generalhandler.cpp:247 +#, no-c-format +msgid "% Critical" +msgstr "% சிக்கலானது" + +#: ../src/net/tmwa/gui/guildtab.cpp:41 +msgid "Guild" +msgstr "கில்ட்" + +#: ../src/net/tmwa/gui/guildtab.cpp:53 ../src/net/tmwa/gui/partytab.cpp:52 +msgid "/help > Display this help." +msgstr "/உதவி> இந்த உதவியைக் காண்பி." + +#: ../src/net/tmwa/gui/guildtab.cpp:54 +msgid "/invite > Invite a player to your guild" +msgstr "/அழைக்கவும்> உங்கள் கில்டுக்கு ஒரு வீரரை அழைக்கவும்" + +#: ../src/net/tmwa/gui/guildtab.cpp:55 +msgid "/leave > Leave the guild you are in" +msgstr "/விடுப்பு> நீங்கள் இருக்கும் கில்டை விட்டு விடுங்கள்" + +#: ../src/net/tmwa/gui/guildtab.cpp:56 +msgid "/kick > Kick someone from the guild you are in" +msgstr "/கிக்> நீங்கள் இருக்கும் கில்டில் இருந்து ஒருவரை உதைக்கவும்" + +#: ../src/net/tmwa/gui/guildtab.cpp:65 ../src/net/tmwa/gui/partytab.cpp:66 +msgid "Command: /invite <nick>" +msgstr "கட்டளை: /அழைக்கவும் <நிக்>" + +#: ../src/net/tmwa/gui/guildtab.cpp:66 +msgid "This command invites <nick> to the guild you're in." +msgstr "இந்த கட்டளை நீங்கள் இருக்கும் கில்டுக்கு <நிக்> ஐ அழைக்கிறது." + +#: ../src/net/tmwa/gui/guildtab.cpp:72 ../src/net/tmwa/gui/partytab.cpp:73 +msgid "Command: /leave" +msgstr "கட்டளை: /விடுப்பு" + +#: ../src/net/tmwa/gui/guildtab.cpp:73 +msgid "This command causes the player to leave the guild." +msgstr "இந்த கட்டளை வீரர் கில்டை விட்டு வெளியேற காரணமாகிறது." + +#: ../src/net/tmwa/gui/guildtab.cpp:81 +msgid "Guild name is missing." +msgstr "கில்ட் பெயர் காணவில்லை." + +#: ../src/net/tmwa/guildhandler.cpp:63 +msgid "Guild creation isn't supported." +msgstr "கில்ட் உருவாக்கம் ஆதரிக்கப்படவில்லை." + +#: ../src/net/tmwa/gui/partytab.cpp:40 +msgid "Party" +msgstr "கட்சி" + +#: ../src/net/tmwa/gui/partytab.cpp:53 +msgid "/invite > Invite a player to your party" +msgstr "/அழைக்கவும்> உங்கள் விருந்துக்கு ஒரு வீரரை அழைக்கவும்" + +#: ../src/net/tmwa/gui/partytab.cpp:54 +msgid "/leave > Leave the party you are in" +msgstr "/விடுப்பு> நீங்கள் இருக்கும் கட்சியை விட்டு விடுங்கள்" + +#: ../src/net/tmwa/gui/partytab.cpp:55 +msgid "/kick > Kick someone from the party you are in" +msgstr "/கிக்> நீங்கள் இருக்கும் விருந்தில் இருந்து ஒருவரை உதைக்கவும்" + +#: ../src/net/tmwa/gui/partytab.cpp:56 +msgid "/item > Show/change party item sharing options" +msgstr "/பொருள்> கட்சி உருப்படி பகிர்வு விருப்பங்களைக் காட்டு/மாற்றவும்" + +#: ../src/net/tmwa/gui/partytab.cpp:57 +msgid "/exp > Show/change party experience sharing options" +msgstr "/exp> கட்சி அனுபவ பகிர்வு விருப்பங்களைக் காட்டு/மாற்றவும்" + +#: ../src/net/tmwa/gui/partytab.cpp:74 +msgid "This command causes the player to leave the party." +msgstr "இந்த கட்டளை வீரர் விருந்தை விட்டு வெளியேற காரணமாகிறது." + +#: ../src/net/tmwa/gui/partytab.cpp:78 +msgid "Command: /item <policy>" +msgstr "கட்டளை: /உருப்படி <கொள்கை>" + +#: ../src/net/tmwa/gui/partytab.cpp:79 +msgid "This command changes the party's item sharing policy." +msgstr "இந்த கட்டளை கட்சியின் உருப்படி பகிர்வு கொள்கையை மாற்றுகிறது." + +#: ../src/net/tmwa/gui/partytab.cpp:80 +msgid "" +"<policy> can be one of \"1\", \"yes\", \"true\" to enable item sharing, or " +"\"0\", \"no\", \"false\" to disable item sharing." +msgstr "" +"<கொள்கை> உருப்படி பகிர்வை இயக்க \"1\", \"ஆம்\", \"உண்மை\" அல்லது உருப்படி பகிர்வை முடக்" +"க \"0\", \"இல்லை\", \"பொய்\" ஆகியவற்றில் ஒன்றாக இருக்கலாம்." + +#: ../src/net/tmwa/gui/partytab.cpp:83 +msgid "Command: /item" +msgstr "கட்டளை: /உருப்படி" + +#: ../src/net/tmwa/gui/partytab.cpp:84 +msgid "This command displays the party's current item sharing policy." +msgstr "இந்த கட்டளை கட்சியின் தற்போதைய உருப்படி பகிர்வு கொள்கையைக் காட்டுகிறது." + +#: ../src/net/tmwa/gui/partytab.cpp:88 +msgid "Command: /exp <policy>" +msgstr "கட்டளை: /எக்ச்ப் <கொள்கை>" + +#: ../src/net/tmwa/gui/partytab.cpp:89 +msgid "This command changes the party's experience sharing policy." +msgstr "இந்த கட்டளை கட்சியின் அனுபவ பகிர்வுக் கொள்கையை மாற்றுகிறது." + +#: ../src/net/tmwa/gui/partytab.cpp:90 +msgid "" +"<policy> can be one of \"1\", \"yes\", \"true\" to enable experience " +"sharing, or \"0\", \"no\", \"false\" to disable experience sharing." +msgstr "" +"<கொள்கை> அனுபவ பகிர்வை இயக்க \"1\", \"ஆம்\", \"உண்மை\" அல்லது அனுபவ பகிர்வை முடக்க " +"\"0\", \"இல்லை\", \"பொய்\" ஆகியவற்றில் ஒன்றாக இருக்கலாம்." + +#: ../src/net/tmwa/gui/partytab.cpp:93 +msgid "Command: /exp" +msgstr "கட்டளை: /exp" + +#: ../src/net/tmwa/gui/partytab.cpp:94 +msgid "This command displays the party's current experience sharing policy." +msgstr "இந்த கட்டளை கட்சியின் தற்போதைய அனுபவ பகிர்வுக் கொள்கையைக் காட்டுகிறது." + +#: ../src/net/tmwa/gui/partytab.cpp:125 ../src/net/tmwa/partyhandler.cpp:196 +msgid "Item sharing enabled." +msgstr "உருப்படி பகிர்வு இயக்கப்பட்டது." + +#: ../src/net/tmwa/gui/partytab.cpp:128 ../src/net/tmwa/partyhandler.cpp:202 +msgid "Item sharing disabled." +msgstr "உருப்படி பகிர்வு முடக்கப்பட்டது." + +#: ../src/net/tmwa/gui/partytab.cpp:131 ../src/net/tmwa/partyhandler.cpp:208 +msgid "Item sharing not possible." +msgstr "உருப்படி பகிர்வு சாத்தியமில்லை." + +#: ../src/net/tmwa/gui/partytab.cpp:134 +msgid "Item sharing unknown." +msgstr "உருப்படி பகிர்வு தெரியவில்லை." + +#: ../src/net/tmwa/gui/partytab.cpp:160 ../src/net/tmwa/partyhandler.cpp:172 +msgid "Experience sharing enabled." +msgstr "அனுபவ பகிர்வு இயக்கப்பட்டது." + +#: ../src/net/tmwa/gui/partytab.cpp:163 ../src/net/tmwa/partyhandler.cpp:178 +msgid "Experience sharing disabled." +msgstr "பட்டறிவு பகிர்வு முடக்கப்பட்டது." + +#: ../src/net/tmwa/gui/partytab.cpp:166 ../src/net/tmwa/partyhandler.cpp:184 +msgid "Experience sharing not possible." +msgstr "பட்டறிவு பகிர்வு சாத்தியமில்லை." + +#: ../src/net/tmwa/gui/partytab.cpp:169 +msgid "Experience sharing unknown." +msgstr "தெரியாத அனுபவத்தைப் பகிர்வது." + +#: ../src/net/tmwa/inventoryhandler.cpp:277 +msgid "Failed to use item." +msgstr "உருப்படியைப் பயன்படுத்தத் தவறிவிட்டது." + +#: ../src/net/tmwa/inventoryhandler.cpp:389 +msgid "Unable to equip." +msgstr "சித்தப்படுத்த முடியவில்லை." + +#: ../src/net/tmwa/inventoryhandler.cpp:401 +msgid "Unable to unequip." +msgstr "அவிழ்க்க முடியவில்லை." + +#: ../src/net/tmwa/inventoryhandler.h:64 +msgid "Torso" +msgstr "உடல்" + +#: ../src/net/tmwa/inventoryhandler.h:66 +msgid "Arms" +msgstr "ஆயுதங்கள்" + +#: ../src/net/tmwa/inventoryhandler.h:68 +msgid "Head" +msgstr "தலை" + +#: ../src/net/tmwa/inventoryhandler.h:70 +msgid "Legs" +msgstr "கால்கள்" + +#: ../src/net/tmwa/inventoryhandler.h:72 +msgid "Feet" +msgstr "அடி" + +#: ../src/net/tmwa/inventoryhandler.h:74 +msgid "Ring 1/2" +msgstr "மோதிரம் 1/2" + +#: ../src/net/tmwa/inventoryhandler.h:76 +msgid "Ring 2/2" +msgstr "மோதிரம் 2/2" + +#: ../src/net/tmwa/inventoryhandler.h:78 +msgid "Necklace" +msgstr "நெக்லச்" + +#: ../src/net/tmwa/inventoryhandler.h:80 +msgid "Hand 1/2" +msgstr "கை 1/2" + +#: ../src/net/tmwa/inventoryhandler.h:82 +msgid "Hand 2/2" +msgstr "கை 2/2" + +#: ../src/net/tmwa/inventoryhandler.h:84 +msgid "Ammo" +msgstr "அம்மோ" + +#: ../src/net/tmwa/loginhandler.cpp:89 +msgid "Account was not found. Please re-login." +msgstr "கணக்கு காணப்படவில்லை. தயவுசெய்து மீண்டும் பதிவு செய்யுங்கள்." + +#: ../src/net/tmwa/loginhandler.cpp:95 +msgid "New password too short." +msgstr "புதிய கடவுச்சொல் மிகக் குறைவு." + +#: ../src/net/tmwa/loginhandler.cpp:160 +msgid "Unregistered ID." +msgstr "பதிவு செய்யப்படாத ஐடி." + +#: ../src/net/tmwa/loginhandler.cpp:163 +msgid "Wrong password." +msgstr "தவறான கடவுச்சொல்." + +#: ../src/net/tmwa/loginhandler.cpp:166 +msgid "Account expired." +msgstr "கணக்கு காலாவதியானது." + +#: ../src/net/tmwa/loginhandler.cpp:169 +msgid "Rejected from server." +msgstr "சேவையகத்திலிருந்து நிராகரிக்கப்பட்டது." + +#: ../src/net/tmwa/loginhandler.cpp:172 +msgid "" +"You have been permanently banned from the game. Please contact the GM team." +msgstr "" +"நீங்கள் விளையாட்டிலிருந்து நிரந்தரமாக தடை செய்யப்பட்டுள்ளீர்கள். GM அணியை தொடர்பு கொள்ளவும்." + +#: ../src/net/tmwa/loginhandler.cpp:176 +msgid "Client too old." +msgstr "கிளையன்ட் மிகவும் பழையது." + +#: ../src/net/tmwa/loginhandler.cpp:179 +#, c-format +msgid "" +"You have been temporarily banned from the game until %s.\n" +"Please contact the GM team via the forums." +msgstr "" +"நீங்கள் தற்காலிகமாக விளையாட்டிலிருந்து %s வரை தடை செய்யப்பட்டுள்ளீர்கள்.\n" +" மன்றங்கள் வழியாக GM குழுவை தொடர்பு கொள்ளவும்." + +#: ../src/net/tmwa/loginhandler.cpp:186 +msgid "Server overpopulated." +msgstr "சேவையகம் அதிக மக்கள் தொகை." + +#: ../src/net/tmwa/loginhandler.cpp:189 +msgid "This user name is already taken." +msgstr "இந்த பயனர் பெயர் ஏற்கனவே எடுக்கப்பட்டுள்ளது." + +#: ../src/net/tmwa/loginhandler.cpp:192 +msgid "Username permanently erased." +msgstr "பயனர்பெயர் நிரந்தரமாக அழிக்கப்பட்டது." + +#: ../src/net/tmwa/network.cpp:289 +msgid "Empty address given to Network::connect()!" +msgstr "நெட்வொர்க்கிற்கு வழங்கப்பட்ட வெற்று முகவரி :: இணைக்கவும் ()!" + +#: ../src/net/tmwa/network.cpp:470 +#, c-format +msgid "Unable to resolve host \"%s\"" +msgstr "புரவலன் \"%s\" ஐ தீர்க்க முடியவில்லை" + +#: ../src/net/tmwa/network.cpp:540 +msgid "Connection to server terminated. " +msgstr "சேவையகத்திற்கான இணைப்பு நிறுத்தப்பட்டது. " + +#: ../src/net/tmwa/partyhandler.cpp:82 +msgid "Could not create party." +msgstr "கட்சியை உருவாக்க முடியவில்லை." + +#: ../src/net/tmwa/partyhandler.cpp:84 +msgid "Party successfully created." +msgstr "கட்சி வெற்றிகரமாக உருவாக்கப்பட்டது." + +#: ../src/net/tmwa/partyhandler.cpp:119 +#, c-format +msgid "%s is already a member of a party." +msgstr "%s ஏற்கனவே ஒரு கட்சியின் உறுப்பினராக உள்ளார்." + +#: ../src/net/tmwa/partyhandler.cpp:123 +#, c-format +msgid "%s refused your invitation." +msgstr "%s உங்கள் அழைப்பை மறுத்துவிட்டன." + +#: ../src/net/tmwa/partyhandler.cpp:127 +#, c-format +msgid "%s is now a member of your party." +msgstr "%s இப்போது உங்கள் கட்சியின் உறுப்பினராக உள்ளார்." + +#: ../src/net/tmwa/partyhandler.cpp:131 +#, c-format +msgid "Unknown invite response for %s." +msgstr "%s க்கான அறியப்படாத அழைப்பு பதில்." + +#: ../src/net/tmwa/partyhandler.cpp:224 +msgid "You have left the party." +msgstr "நீங்கள் கட்சியை விட்டு வெளியேறிவிட்டீர்கள்." + +#: ../src/net/tmwa/partyhandler.cpp:234 +#, c-format +msgid "%s has left your party." +msgstr "%s உங்கள் கட்சியை விட்டு வெளியேறிவிட்டன." + +#: ../src/net/tmwa/partyhandler.cpp:287 +#, c-format +msgid "An unknown member tried to say: %s" +msgstr "தெரியாத உறுப்பினர் சொல்ல முயன்றார்: %s" + +#: ../src/net/tmwa/partyhandler.cpp:323 +#, c-format +msgid "Inviting failed, because you can't see a player called %s." +msgstr "" +"அழைப்பது தோல்வியுற்றது, ஏனென்றால் %s என்று அழைக்கப்படும் ஒரு வீரரை நீங்கள் பார்க்க முடியாது." + +#: ../src/net/tmwa/partyhandler.cpp:328 +msgid "You can only invite when you are in a party!" +msgstr "நீங்கள் ஒரு விருந்தில் இருக்கும்போது மட்டுமே அழைக்க முடியும்!" + +#: ../src/net/tmwa/partyhandler.cpp:356 +#, c-format +msgid "%s is not in your party!" +msgstr "%s உங்கள் கட்சியில் இல்லை!" + +#: ../src/net/tmwa/playerhandler.cpp:100 +msgid "Insert coin to continue." +msgstr "தொடர நாணயத்தை செருகவும்." + +#: ../src/net/tmwa/playerhandler.cpp:118 +msgid "You're not dead yet. You're just resting." +msgstr "நீங்கள் இன்னும் இறந்துவிடவில்லை. நீங்கள் ஓய்வெடுக்கிறீர்கள்." + +#: ../src/net/tmwa/playerhandler.cpp:119 +msgid "You are no more." +msgstr "நீங்கள் இனி இல்லை." + +#: ../src/net/tmwa/playerhandler.cpp:120 +msgid "You have ceased to be." +msgstr "நீங்கள் இருப்பதை நிறுத்திவிட்டீர்கள்." + +#: ../src/net/tmwa/playerhandler.cpp:121 +msgid "You've expired and gone to meet your maker." +msgstr "உங்கள் தயாரிப்பாளரை சந்திக்க நீங்கள் காலாவதியானீர்கள்." + +#: ../src/net/tmwa/playerhandler.cpp:122 +msgid "You're a stiff." +msgstr "நீங்கள் ஒரு கடினமானவர்." + +#: ../src/net/tmwa/playerhandler.cpp:123 +msgid "Bereft of life, you rest in peace." +msgstr "வாழ்க்கையின் வெறுப்பு, நீங்கள் நிம்மதியாக ஓய்வெடுக்கிறீர்கள்." + +#: ../src/net/tmwa/playerhandler.cpp:124 +msgid "If you weren't so animated, you'd be pushing up the daisies." +msgstr "" +"நீங்கள் அவ்வளவு அனிமேசன் செய்யப்படவில்லை என்றால், நீங்கள் டெய்சிசை உயர்த்துவீர்கள்." + +#: ../src/net/tmwa/playerhandler.cpp:125 +msgid "Your metabolic processes are now history." +msgstr "உங்கள் வளர்சிதை மாற்ற செயல்முறைகள் இப்போது வரலாறு." + +#: ../src/net/tmwa/playerhandler.cpp:126 +msgid "You're off the twig." +msgstr "நீங்கள் கிளையிலிருந்து விலகிவிட்டீர்கள்." + +#: ../src/net/tmwa/playerhandler.cpp:127 +msgid "You've kicked the bucket." +msgstr "நீங்கள் வாளியை உதைத்தீர்கள்." + +#: ../src/net/tmwa/playerhandler.cpp:128 +msgid "" +"You've shuffled off your mortal coil, run down the curtain and joined the " +"bleedin' choir invisible." +msgstr "" +"நீங்கள் உங்கள் மரண சுருளை மாற்றி, திரைச்சீலை ஓடி, இரத்தப்போக்கு 'பாடகர் கண்ணுக்கு " +"தெரியாதவற்றில் சேர்ந்தீர்கள்." + +#: ../src/net/tmwa/playerhandler.cpp:130 +msgid "You are an ex-player." +msgstr "நீங்கள் ஒரு முன்னாள் வீரர்." + +#: ../src/net/tmwa/playerhandler.cpp:131 +msgid "You're pining for the fjords." +msgstr "நீங்கள் fjords க்காக பைட்டிங் செய்கிறீர்கள்." + +#: ../src/net/tmwa/playerhandler.cpp:253 ../src/net/tmwa/playerhandler.cpp:293 +msgid "Message" +msgstr "செய்தி" + +#: ../src/net/tmwa/playerhandler.cpp:254 +msgid "" +"You are carrying more than half your weight. You are unable to regain health." +msgstr "" +"உங்கள் எடைக்கு பாதிக்கும் மேற்பட்டவற்றை நீங்கள் சுமக்கிறீர்கள். நீங்கள் ஆரோக்கியத்தை மீண்டும் பெற " +"முடியவில்லை." + +#: ../src/net/tmwa/playerhandler.cpp:326 +#, c-format +msgid "You picked up %s." +msgstr "நீங்கள் %s எடுத்தீர்கள்." + +#: ../src/net/tmwa/playerhandler.cpp:361 +msgid "Cannot raise skill!" +msgstr "திறனை உயர்த்த முடியாது!" + +#: ../src/net/tmwa/playerhandler.cpp:499 +msgid "Equip arrows first." +msgstr "அம்புகளை முதலில் சித்தப்படுத்துங்கள்." + +#: ../src/net/tmwa/specialhandler.cpp:143 +msgid "Trade failed!" +msgstr "வணிகம் தோல்வியடைந்தது!" + +#: ../src/net/tmwa/specialhandler.cpp:146 +msgid "Emote failed!" +msgstr "எமோட் தோல்வியுற்றது!" + +#: ../src/net/tmwa/specialhandler.cpp:149 +msgid "Sit failed!" +msgstr "உட்கார்ந்து தோல்வியடைந்தார்!" + +#: ../src/net/tmwa/specialhandler.cpp:152 +msgid "Chat creating failed!" +msgstr "அரட்டை உருவாக்குவது தோல்வியுற்றது!" + +#: ../src/net/tmwa/specialhandler.cpp:155 +msgid "Could not join party!" +msgstr "விருந்தில் சேர முடியவில்லை!" + +#: ../src/net/tmwa/specialhandler.cpp:158 +msgid "Cannot shout!" +msgstr "கூச்சலிட முடியாது!" + +#: ../src/net/tmwa/specialhandler.cpp:167 +msgid "You have not yet reached a high enough lvl!" +msgstr "நீங்கள் இன்னும் போதுமான அளவு எல்விஎல்லை எட்டவில்லை!" + +#: ../src/net/tmwa/specialhandler.cpp:170 +msgid "Insufficient HP!" +msgstr "போதுமான எச்பி!" + +#: ../src/net/tmwa/specialhandler.cpp:173 +msgid "Insufficient SP!" +msgstr "போதிய எச்பி!" + +#: ../src/net/tmwa/specialhandler.cpp:176 +msgid "You have no memos!" +msgstr "உங்களிடம் மெமோக்கள் இல்லை!" + +#: ../src/net/tmwa/specialhandler.cpp:179 +msgid "You cannot do that right now!" +msgstr "நீங்கள் இப்போது அதை செய்ய முடியாது!" + +#: ../src/net/tmwa/specialhandler.cpp:182 +msgid "Seems you need more money... ;-)" +msgstr "உங்களுக்கு அதிக பணம் தேவை என்று தெரிகிறது ... ;-)" + +#: ../src/net/tmwa/specialhandler.cpp:185 +msgid "You cannot use this skill with that kind of weapon!" +msgstr "இந்த வகையான ஆயுதத்துடன் இந்த திறமையை நீங்கள் பயன்படுத்த முடியாது!" + +#: ../src/net/tmwa/specialhandler.cpp:188 +msgid "You need another red gem!" +msgstr "உங்களுக்கு மற்றொரு சிவப்பு மாணிக்கம் தேவை!" + +#: ../src/net/tmwa/specialhandler.cpp:191 +msgid "You need another blue gem!" +msgstr "உங்களுக்கு மற்றொரு நீல ரத்தினம் தேவை!" + +#: ../src/net/tmwa/specialhandler.cpp:194 +msgid "You're carrying to much to do this!" +msgstr "இதைச் செய்ய நீங்கள் அதிகம் செல்கிறீர்கள்!" + +#: ../src/net/tmwa/specialhandler.cpp:197 +msgid "Huh? What's that?" +msgstr "ஊ? அது என்ன?" + +#: ../src/net/tmwa/specialhandler.cpp:206 +msgid "Warp failed..." +msgstr "வார்ப் தோல்வியுற்றார் ..." + +#: ../src/net/tmwa/specialhandler.cpp:209 +msgid "Could not steal anything..." +msgstr "எதையும் திருட முடியவில்லை ..." + +#: ../src/net/tmwa/specialhandler.cpp:212 +msgid "Poison had no effect..." +msgstr "நஞ்சு எந்த விளைவையும் ஏற்படுத்தவில்லை ..." + +#: ../src/net/tmwa/tradehandler.cpp:126 +msgid "Trading isn't possible. Trade partner is too far away." +msgstr "வணிகம் சாத்தியமில்லை. வர்த்தக பங்குதாரர் மிகவும் தொலைவில் உள்ளது." + +#: ../src/net/tmwa/tradehandler.cpp:130 +msgid "Trading isn't possible. Character doesn't exist." +msgstr "வணிகம் சாத்தியமில்லை. எழுத்து இல்லை." + +#: ../src/net/tmwa/tradehandler.cpp:134 +msgid "Trade cancelled due to an unknown reason." +msgstr "அறியப்படாத காரணம் காரணமாக வணிகம் ரத்து செய்யப்பட்டது." + +#: ../src/net/tmwa/tradehandler.cpp:139 +#, c-format +msgid "Trade: You and %s" +msgstr "வர்த்தகம்: நீங்களும் %s" + +#: ../src/net/tmwa/tradehandler.cpp:147 +#, c-format +msgid "Trade with %s cancelled." +msgstr "%s ரத்துசெய்யப்பட்ட வணிகம்." + +#: ../src/net/tmwa/tradehandler.cpp:156 +msgid "Unhandled trade cancel packet." +msgstr "தடையற்ற வர்த்தக ரத்து பாக்கெட்டை." + +#: ../src/net/tmwa/tradehandler.cpp:204 +msgid "Failed adding item. Trade partner is over weighted." +msgstr "உருப்படியைச் சேர்ப்பதில் தோல்வி. வர்த்தக பங்குதாரர் எடையுள்ளவர்." + +#: ../src/net/tmwa/tradehandler.cpp:209 +msgid "Failed adding item. Trade partner has no free slot." +msgstr "" +"உருப்படியைச் சேர்ப்பதில் தோல்வி. வர்த்தக கூட்டாளருக்கு இலவச ச்லாட் இல்லை." + +#: ../src/net/tmwa/tradehandler.cpp:214 +msgid "Failed adding item. You can't trade this item." +msgstr "" +"உருப்படியைச் சேர்ப்பதில் தோல்வி. இந்த உருப்படியை நீங்கள் வணிகம் செய்ய முடியாது." + +#: ../src/net/tmwa/tradehandler.cpp:218 +msgid "Failed adding item for unknown reason." +msgstr "அறியப்படாத காரணத்திற்காக உருப்படியைச் சேர்ப்பதில் தோல்வி." + +#: ../src/playerrelations.cpp:316 +msgid "Completely ignore" +msgstr "முற்றிலும் புறக்கணிக்கவும்" + +#: ../src/playerrelations.cpp:330 +msgid "Print '...'" +msgstr "அச்சு '...'" + +#: ../src/playerrelations.cpp:346 +msgid "Blink name" +msgstr "ஒளிரும் பெயர்" + +#: ../src/resources/attributes.cpp:165 +#, c-format +msgid "Strength %+.1f" +msgstr "வலிமை %+.1f" + +#: ../src/resources/attributes.cpp:177 +#, c-format +msgid "Agility %+.1f" +msgstr "சுறுசுறுப்பு %+.1f" + +#: ../src/resources/attributes.cpp:189 +#, c-format +msgid "Dexterity %+.1f" +msgstr "திறமை %+.1f" + +#: ../src/resources/attributes.cpp:201 +#, c-format +msgid "Vitality %+.1f" +msgstr "உயிர்ச்சக்தி %+.1f" + +#: ../src/resources/attributes.cpp:213 +#, c-format +msgid "Intelligence %+.1f" +msgstr "நுண்ணறிவு %+.1f" + +#: ../src/resources/attributes.cpp:219 +msgid "Willpower" +msgstr "மன உறுதி" + +#: ../src/resources/attributes.cpp:225 +#, c-format +msgid "Willpower %+.1f" +msgstr "மன உறுதியான %+.1f" + +#: ../src/resources/beinginfo.cpp:34 ../src/resources/itemdb.cpp:241 +#: ../src/resources/monsterdb.cpp:74 +msgid "unnamed" +msgstr "பெயரில்லாதது" + +#: ../src/resources/itemdb.cpp:66 +msgid "Unknown item" +msgstr "தெரியாத உருப்படி" + +#: ../src/resources/itemdb.cpp:290 +#, c-format +msgid "Attack %+d" +msgstr "தாக்குதல் %+d" + +#: ../src/resources/itemdb.cpp:291 +#, c-format +msgid "Defense %+d" +msgstr "பாதுகாப்பு %+d" + +#: ../src/resources/itemdb.cpp:292 +#, c-format +msgid "HP %+d" +msgstr "எச்பி %+d" + +#: ../src/resources/itemdb.cpp:293 +#, c-format +msgid "MP %+d" +msgstr "Mp %+d" + +#: ../src/resources/userpalette.cpp:86 +msgid "Being" +msgstr "இருப்பது" + +#: ../src/resources/userpalette.cpp:87 +msgid "Other Players' Names" +msgstr "மற்ற வீரர்களின் பெயர்கள்" + +#: ../src/resources/userpalette.cpp:88 +msgid "Own Name" +msgstr "சொந்த பெயர்" + +#: ../src/resources/userpalette.cpp:89 +msgid "GM Names" +msgstr "GM பெயர்கள்" + +#: ../src/resources/userpalette.cpp:90 +msgid "NPCs" +msgstr "NPCS" + +#: ../src/resources/userpalette.cpp:91 +msgid "Monsters" +msgstr "அரக்கர்கள்" + +#: ../src/resources/userpalette.cpp:92 +msgid "Party Members" +msgstr "கட்சி உறுப்பினர்கள்" + +#: ../src/resources/userpalette.cpp:93 +msgid "Guild Members" +msgstr "கில்ட் உறுப்பினர்கள்" + +#: ../src/resources/userpalette.cpp:94 +msgid "Particle Effects" +msgstr "துகள் விளைவுகள்" + +#: ../src/resources/userpalette.cpp:95 +msgid "Pickup Notification" +msgstr "இடும் அறிவிப்பு" + +#: ../src/resources/userpalette.cpp:96 +msgid "Exp Notification" +msgstr "எக்ச்ப் அறிவிப்பு" + +#: ../src/resources/userpalette.cpp:98 +msgid "Other Player Hits Monster" +msgstr "மற்ற வீரர் அசுரனைத் தாக்கினார்" + +#: ../src/resources/userpalette.cpp:99 +msgid "Monster Hits Player" +msgstr "மான்ச்டர் வீரரைத் தாக்கினார்" + +#: ../src/resources/userpalette.cpp:100 +msgid "Critical Hit" +msgstr "சிக்கலான செய்" + +#: ../src/resources/userpalette.cpp:102 +msgid "Local Player Hits Monster" +msgstr "உள்ளக வீரர் அசுரனைத் தாக்கினார்" + +#: ../src/resources/userpalette.cpp:104 +msgid "Local Player Critical Hit" +msgstr "உள்ளக வீரர் விமர்சன செய்" + +#: ../src/resources/userpalette.cpp:106 +msgid "Local Player Miss" +msgstr "உள்ளக வீரர் மிச்" + +#: ../src/resources/userpalette.cpp:107 +msgid "Misses" +msgstr "மிச்" @@ -3763,7 +3763,7 @@ msgstr "" #: ../src/net/tmwa/playerhandler.cpp:128 msgid "" "You've shuffled off your mortal coil, run down the curtain and joined the " -"bleedin' choir invisibile." +"bleedin' choir invisible." msgstr "" #: ../src/net/tmwa/playerhandler.cpp:125 @@ -3760,7 +3760,7 @@ msgstr "" #: ../src/net/tmwa/playerhandler.cpp:128 msgid "" "You've shuffled off your mortal coil, run down the curtain and joined the " -"bleedin' choir invisibile." +"bleedin' choir invisible." msgstr "" #: ../src/net/tmwa/playerhandler.cpp:125 @@ -3839,7 +3839,7 @@ msgstr "" #: ../src/net/tmwa/playerhandler.cpp:128 msgid "" "You've shuffled off your mortal coil, run down the curtain and joined the " -"bleedin' choir invisibile." +"bleedin' choir invisible." msgstr "" #: ../src/net/tmwa/playerhandler.cpp:125 @@ -3921,7 +3921,7 @@ msgstr "" #: ../src/net/tmwa/playerhandler.cpp:128 msgid "" "You've shuffled off your mortal coil, run down the curtain and joined the " -"bleedin' choir invisibile." +"bleedin' choir invisible." msgstr "" #: ../src/net/tmwa/playerhandler.cpp:125 diff --git a/po/zh_CN.po b/po/zh_CN.po index 4748494b..c8e581e5 100644 --- a/po/zh_CN.po +++ b/po/zh_CN.po @@ -3965,7 +3965,7 @@ msgstr "" #: ../src/net/tmwa/playerhandler.cpp:128 msgid "" "You've shuffled off your mortal coil, run down the curtain and joined the " -"bleedin' choir invisibile." +"bleedin' choir invisible." msgstr "" #: ../src/net/tmwa/playerhandler.cpp:125 diff --git a/po/zh_HK.po b/po/zh_HK.po index 92983e59..dea75c3d 100644 --- a/po/zh_HK.po +++ b/po/zh_HK.po @@ -3832,7 +3832,7 @@ msgstr "" #: ../src/net/tmwa/playerhandler.cpp:128 msgid "" "You've shuffled off your mortal coil, run down the curtain and joined the " -"bleedin' choir invisibile." +"bleedin' choir invisible." msgstr "" #: ../src/net/tmwa/playerhandler.cpp:125 diff --git a/po/zh_TW.po b/po/zh_TW.po index 85b94c8e..d861bf95 100644 --- a/po/zh_TW.po +++ b/po/zh_TW.po @@ -3962,7 +3962,7 @@ msgstr "你踢了水桶" #: ../src/net/tmwa/playerhandler.cpp:128 msgid "" "You've shuffled off your mortal coil, run down the curtain and joined the " -"bleedin' choir invisibile." +"bleedin' choir invisible." msgstr "死掉了...." #: ../src/net/tmwa/playerhandler.cpp:125 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4a6a93db..8738a41b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -4,7 +4,7 @@ pkg_check_modules(SDL2 REQUIRED SDL2_image SDL2_mixer SDL2_net - SDL2_ttf) + SDL2_ttf>=2.0.12) find_package(PhysFS REQUIRED) find_package(CURL REQUIRED) find_package(LibXml2 REQUIRED) @@ -230,6 +230,8 @@ set(SRCS gui/palette.h gui/popupmenu.cpp gui/popupmenu.h + gui/questswindow.cpp + gui/questswindow.h gui/quitdialog.cpp gui/quitdialog.h gui/recorder.cpp @@ -346,6 +348,8 @@ set(SRCS resources/music.h resources/npcdb.cpp resources/npcdb.h + resources/questdb.cpp + resources/questdb.h resources/resource.cpp resources/resource.h resources/resourcemanager.cpp @@ -495,7 +499,6 @@ set(SRCS textmanager.h textparticle.cpp textparticle.h - textrenderer.h tileset.h units.cpp units.h diff --git a/src/actorsprite.cpp b/src/actorsprite.cpp index 7cb46bd4..f31297e9 100644 --- a/src/actorsprite.cpp +++ b/src/actorsprite.cpp @@ -213,7 +213,7 @@ void ActorSprite::loadTargetCursor(const std::string &filename, auto currentImageSet = resman->getImageSet(filename, width, height); if (!currentImageSet) { - logger->log("Error loading target cursor: %s", filename.c_str()); + Log::info("Error loading target cursor: %s", filename.c_str()); return; } diff --git a/src/being.cpp b/src/being.cpp index 46b67f4b..91fe4bc0 100644 --- a/src/being.cpp +++ b/src/being.cpp @@ -481,15 +481,15 @@ void Being::setShowName(bool doShowName) void Being::setGuildName(const std::string &name) { - logger->log("Got guild name \"%s\" for being %s(%i)", name.c_str(), - mName.c_str(), mId); + Log::info("Got guild name \"%s\" for being %s(%i)", name.c_str(), + mName.c_str(), mId); } void Being::setGuildPos(const std::string &pos) { - logger->log("Got guild position \"%s\" for being %s(%i)", pos.c_str(), - mName.c_str(), mId); + Log::info("Got guild position \"%s\" for being %s(%i)", pos.c_str(), + mName.c_str(), mId); } void Being::addGuild(Guild *guild) diff --git a/src/being.h b/src/being.h index 80620e71..43cc546c 100644 --- a/src/being.h +++ b/src/being.h @@ -166,7 +166,7 @@ class Being : public ActorSprite, public EventListener, public gcn::DeathListene * Puts a damage bubble above this being. * * @param attacker the attacking being - * @param damage the amount of damage recieved (0 means miss) + * @param damage the amount of damage received (0 means miss) * @param type the attack type * @param attackId the attack id (used for monsters) */ diff --git a/src/chatlogger.cpp b/src/chatlogger.cpp index 119d3fc1..854f9780 100644 --- a/src/chatlogger.cpp +++ b/src/chatlogger.cpp @@ -38,6 +38,51 @@ #include "utils/stringutils.h" +static std::string getDateString() +{ + time_t t = time(nullptr); + struct tm *now = localtime(&t); + char buffer[11]; + strftime(buffer, sizeof(buffer), "%Y-%m-%d", now); + return buffer; +} + +static std::string &secureName(std::string &name) +{ + const size_t sz = name.length(); + for (size_t f = 0; f < sz; f ++) + { + const unsigned char ch = name[f]; + if ((ch < '0' || ch > '9') && + (ch < 'a' || ch > 'z') && + (ch < 'A' || ch > 'Z') && + ch != '-' && + ch != '+' && + ch != '=' && + ch != '.' && + ch != ',' && + ch != ')' && + ch != '(' && + ch != '[' && + ch != ']' && + ch != '#') + { + name[f] = '_'; + } + } + return name; +} + +static void makeDir(const std::string &dir) +{ +#ifdef _WIN32 + mkdir(dir.c_str()); +#else + mkdir(dir.c_str(), S_IRWXU | S_IRGRP | S_IXGRP); +#endif +} + + ChatLogger::~ChatLogger() = default; void ChatLogger::setLogFile(const std::string &logFilename) @@ -74,69 +119,32 @@ void ChatLogger::log(std::string str) if (!mLogFile.is_open() || dateStr != mLogDate) { mLogDate = dateStr; - setLogFile(strprintf("%s/%s/#General_%s.log", mLogDir.c_str(), - mServerName.c_str(), dateStr.c_str())); + setLogFile(strprintf("%s/%s/#General_%s.log", + mLogDir.c_str(), + mServerName.c_str(), + dateStr.c_str())); } removeColors(str); - writeTo(mLogFile, str); + mLogFile << str << std::endl; } void ChatLogger::log(std::string name, std::string str) { std::ofstream logFile; - logFile.open(strprintf("%s/%s/%s_%s.log", mLogDir.c_str(), mServerName.c_str(), - secureName(name).c_str(), getDateString().c_str()).c_str(), + logFile.open(strprintf("%s/%s/%s_%s.log", + mLogDir.c_str(), + mServerName.c_str(), + secureName(name).c_str(), + getDateString().c_str()) + .c_str(), std::ios_base::app); if (!logFile.is_open()) return; removeColors(str); - writeTo(logFile, str); - - if (logFile.is_open()) - logFile.close(); -} - -std::string ChatLogger::getDateString() -{ - time_t t = time(nullptr); - struct tm *now = localtime(&t); - char buffer[11]; - strftime(buffer, sizeof(buffer), "%Y-%m-%d", now); - return buffer; -} - -std::string ChatLogger::secureName(std::string &name) -{ - const size_t sz = name.length(); - for (size_t f = 0; f < sz; f ++) - { - const unsigned char ch = name[f]; - if ((ch < '0' || ch > '9') && - (ch < 'a' || ch > 'z') && - (ch < 'A' || ch > 'Z') && - ch != '-' && - ch != '+' && - ch != '=' && - ch != '.' && - ch != ',' && - ch != ')' && - ch != '(' && - ch != '[' && - ch != ']' && - ch != '#') - { - name[f] = '_'; - } - } - return name; -} - -void ChatLogger::writeTo(std::ofstream &file, const std::string &str) -{ - file << str << std::endl; + logFile << str << std::endl; } void ChatLogger::setServerName(const std::string &serverName) @@ -158,12 +166,3 @@ void ChatLogger::setServerName(const std::string &serverName) closedir(dir); } } - -void ChatLogger::makeDir(const std::string &dir) -{ -#ifdef _WIN32 - mkdir(dir.c_str()); -#else - mkdir(dir.c_str(), S_IRWXU | S_IRGRP | S_IXGRP); -#endif -} diff --git a/src/chatlogger.h b/src/chatlogger.h index 59d9f28c..8e4118dc 100644 --- a/src/chatlogger.h +++ b/src/chatlogger.h @@ -35,13 +35,8 @@ class ChatLogger * Enters a message in the log. The message will be timestamped. */ void log(std::string str); - void log(std::string name, std::string str); - static std::string getDateString(); - - static std::string secureName(std::string &str); - void setServerName(const std::string &serverName); private: @@ -50,10 +45,6 @@ class ChatLogger */ void setLogFile(const std::string &logFilename); - static void writeTo(std::ofstream &file, const std::string &str); - - static void makeDir(const std::string &dir); - std::ofstream mLogFile; std::string mLogDir; std::string mServerName; diff --git a/src/client.cpp b/src/client.cpp index f0254d50..7c8763a1 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -29,6 +29,7 @@ #include "game.h" #include "itemshortcut.h" #include "keyboardconfig.h" +#include "log.h" #include "playerrelations.h" #include "sound.h" @@ -87,6 +88,8 @@ #include <sys/stat.h> #include <cassert> +#include <guichan/exception.hpp> + // TODO: Get rid of these globals std::string errorMessage; LoginData loginData; @@ -94,7 +97,6 @@ LoginData loginData; Config config; /**< Global settings (config.xml) */ Configuration branding; /**< XML branding information reader */ Configuration paths; /**< XML default paths information reader */ -Logger *logger; /**< Log object */ ChatLogger *chatLogger; /**< Chat log object */ KeyboardConfig keyboard; @@ -113,7 +115,7 @@ volatile int frame_count = 0; /**< Counts the frames during one second */ * Updates fps. * Called every seconds by SDL_AddTimer() */ -Uint32 nextSecond(Uint32 interval, void *param) +static Uint32 nextSecond(Uint32 interval, void *param) { fps = frame_count; frame_count = 0; @@ -174,8 +176,6 @@ Client::Client(const Options &options): assert(!mInstance); mInstance = this; - logger = new Logger; - // Set default values for configuration files branding.setDefaultValues(getBrandingDefaults()); paths.setDefaultValues(getPathsDefaults()); @@ -190,19 +190,18 @@ Client::Client(const Options &options): initHomeDir(); initConfiguration(); + // Configure logger + Log::init(); + Log::setLogFile(mLocalDataDir + "/mana.log"); + Log::setLogToStandardOut(config.logToStandardOut); + Log::info("%s", FULL_VERSION); + chatLogger = new ChatLogger; if (options.chatLogDir.empty()) chatLogger->setLogDir(mLocalDataDir + "/logs/"); else chatLogger->setLogDir(options.chatLogDir); - // Configure logger - logger->setLogFile(mLocalDataDir + "/mana.log"); - logger->setLogToStandardOut(config.logToStandardOut); - - // Log the mana version - logger->log("%s", FULL_VERSION); - initScreenshotDir(); #if SDL_VERSION_ATLEAST(2, 24, 0) @@ -210,10 +209,10 @@ Client::Client(const Options &options): #endif // Initialize SDL - logger->log("Initializing SDL..."); + Log::info("Initializing SDL..."); if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0) { - logger->error(strprintf("Could not initialize SDL: %s", + Log::critical(strprintf("Could not initialize SDL: %s", SDL_GetError())); } atexit(SDL_Quit); @@ -222,7 +221,7 @@ Client::Client(const Options &options): if (!FS::setWriteDir(mLocalDataDir)) { - logger->error(strprintf("%s couldn't be set as write directory! " + Log::critical(strprintf("%s couldn't be set as write directory! " "Exiting.", mLocalDataDir.c_str())); } @@ -285,7 +284,7 @@ Client::Client(const Options &options): iconFile += ".png"; #endif iconFile = ResourceManager::getPath(iconFile); - logger->log("Loading icon from file: %s", iconFile.c_str()); + Log::info("Loading icon from file: %s", iconFile.c_str()); #ifdef _WIN32 static SDL_SysWMinfo pInfo; SDL_GetWindowWMInfo(mVideo.window(), &pInfo); @@ -327,7 +326,7 @@ Client::Client(const Options &options): { mState = STATE_ERROR; errorMessage = err; - logger->log("Warning: %s", err); + Log::warn("%s", err); } // Initialize keyboard @@ -423,15 +422,13 @@ Client::~Client() SDL_FreeSurface(mIcon); - logger->log("Quitting"); + Log::info("Quitting"); delete userPalette; XML::Writer writer(mConfigDir + "/config.xml"); if (writer.isValid()) serialize(writer, config); - delete logger; - mInstance = nullptr; } @@ -441,506 +438,533 @@ int Client::exec() while (mState != STATE_EXIT) { - Time::beginFrame(); - - if (mGame) + // Handle SDL events + SDL_Event event; + while (SDL_PollEvent(&event)) { - // Let the game handle the events while it is active - mGame->handleInput(); - } - else - { - // Handle SDL events - SDL_Event event; - while (SDL_PollEvent(&event)) + switch (event.type) { - switch (event.type) - { - case SDL_QUIT: - mState = STATE_EXIT; - break; - - case SDL_WINDOWEVENT: - switch (event.window.event) { - case SDL_WINDOWEVENT_SIZE_CHANGED: - handleWindowSizeChanged(event.window.data1, - event.window.data2); - break; - } + case SDL_QUIT: + mState = STATE_EXIT; + break; + + case SDL_WINDOWEVENT: + switch (event.window.event) { + case SDL_WINDOWEVENT_SIZE_CHANGED: + handleWindowSizeChanged(event.window.data1, + event.window.data2); break; + } + break; - case SDL_KEYDOWN: - if (keyboard.isEnabled()) + case SDL_KEYDOWN: + if (keyboard.isEnabled()) + { + const int tKey = keyboard.getKeyIndex(event.key.keysym.sym); + if (tKey == KeyboardConfig::KEY_WINDOW_SETUP) { - const int tKey = keyboard.getKeyIndex(event.key.keysym.sym); - if (tKey == KeyboardConfig::KEY_WINDOW_SETUP) - { - setupWindow->setVisible(!setupWindow->isVisible()); - if (setupWindow->isVisible()) - setupWindow->requestMoveToTop(); - continue; - } + setupWindow->setVisible(!setupWindow->isVisible()); + if (setupWindow->isVisible()) + setupWindow->requestMoveToTop(); + continue; } - break; } - guiInput->pushInput(event); - } - } - - if (Net::getGeneralHandler()) - Net::getGeneralHandler()->flushNetwork(); - - gui->logic(); - if (mGame) - mGame->logic(); - - sound.logic(); - - // Update the screen when application is active, delay otherwise. - if (isActive()) - { - frame_count++; - gui->draw(); - graphics->updateScreen(); - mFpsManager.limitFps(config.fpsLimit); - } - else - { - mFpsManager.limitFps(10); - } - - // TODO: Add connect timeouts - if (mState == STATE_CONNECT_GAME && - Net::getGameHandler()->isConnected()) - { - Net::getLoginHandler()->disconnect(); - } - else if (mState == STATE_CONNECT_SERVER && - mOldState == STATE_CONNECT_SERVER && - Net::getLoginHandler()->isConnected()) - { - mState = STATE_LOGIN; - } - else if (mState == STATE_WORLD_SELECT && mOldState == STATE_UPDATE) - { - if (Net::getLoginHandler()->getWorlds().size() < 2) - { - mState = STATE_LOGIN; - } - } - else if (mOldState == STATE_START || - (mOldState == STATE_GAME && mState != STATE_GAME)) - { - auto *top = static_cast<gcn::Container*>(gui->getTop()); - - mDesktop = new Desktop; - top->add(mDesktop); - mSetupButton = new Button("", "Setup", this); - mSetupButton->setButtonPopupText(_("Setup")); - mSetupButton->setButtonIcon("button-icon-setup.png"); - mSetupButton->setPosition(top->getWidth() - mSetupButton->getWidth() - - 3, 3); - top->add(mSetupButton); - - mDesktop->setSize(graphics->getWidth(), graphics->getHeight()); - } + if (setupWindow->isVisible() && + keyboard.getNewKeyIndex() > KeyboardConfig::KEY_NO_VALUE) + { + keyboard.setNewKey(event.key.keysym.sym); + keyboard.callbackNewKey(); + keyboard.setNewKeyIndex(KeyboardConfig::KEY_NO_VALUE); + continue; + } - if (mState == STATE_SWITCH_LOGIN && mOldState == STATE_GAME) - { - Net::getGameHandler()->disconnect(); - } + // Check whether the game will handle the event + if (mGame && mGame->keyDownEvent(event.key)) + continue; - if (mState != mOldState) - { - { - Event event(Event::StateChange); - event.setInt("oldState", mOldState); - event.setInt("newState", mState); - event.trigger(Event::ClientChannel); + break; } - if (mOldState == STATE_GAME) + // Push input to GUI when not used + try { - delete mGame; - mGame = nullptr; + guiInput->pushInput(event); } - - mOldState = mState; - - // Get rid of the dialog of the previous state - if (mCurrentDialog) + catch (gcn::Exception e) { - delete mCurrentDialog; - mCurrentDialog = nullptr; + const char *err = e.getMessage().c_str(); + Log::warn("Guichan input exception: %s", err); } - // State has changed, while the quitDialog was active, it might - // not be correct anymore - if (mQuitDialog) - mQuitDialog->scheduleDelete(); + } - switch (mState) - { - case STATE_CHOOSE_SERVER: - logger->log("State: CHOOSE SERVER"); + update(); + } - // Don't allow an alpha opacity - // lower than the default value - gui->getTheme()->setMinimumOpacity(0.8f); + Net::unload(); - mCurrentDialog = new ServerDialog(&mCurrentServer, - mConfigDir); - break; + return 0; +} - case STATE_CONNECT_SERVER: - logger->log("State: CONNECT SERVER"); +void Client::update() +{ + Time::beginFrame(); - Net::connectToServer(mCurrentServer); + mVideo.updateWindowSize(); + checkGraphicsSize(); - mCurrentDialog = new ConnectionDialog( - _("Connecting to server"), STATE_SWITCH_SERVER); - break; + // Let the game handle continuous input while it is active + if (mGame) + mGame->handleInput(); - case STATE_LOGIN: - logger->log("State: LOGIN"); - // Don't allow an alpha opacity - // lower than the default value - gui->getTheme()->setMinimumOpacity(0.8f); + if (Net::getGeneralHandler()) + Net::getGeneralHandler()->flushNetwork(); - if (mOptions.username.empty() || mOptions.password.empty()) - { - mCurrentDialog = new LoginDialog(&loginData); - } - else - { - mState = STATE_LOGIN_ATTEMPT; - // Clear the password so that when login fails, the - // dialog will show up next time. - mOptions.password.clear(); - } - break; + gui->logic(); + if (mGame) + mGame->logic(); - case STATE_LOGIN_ATTEMPT: - logger->log("State: LOGIN ATTEMPT"); - accountLogin(&loginData); - mCurrentDialog = new ConnectionDialog( - _("Logging in"), STATE_SWITCH_SERVER); - break; + sound.logic(); - case STATE_WORLD_SELECT: - logger->log("State: WORLD SELECT"); - { - Worlds worlds = Net::getLoginHandler()->getWorlds(); - - if (worlds.empty()) - { - // Trust that the netcode knows what it's doing - mState = STATE_UPDATE; - } - else if (worlds.size() == 1 || mOptions.chooseDefault) - { - Net::getLoginHandler()->chooseServer(0); - mState = STATE_UPDATE; - } - else - { - mCurrentDialog = new WorldSelectDialog(std::move(worlds)); - } - } - break; + // Update the screen when application is active, delay otherwise. + if (isActive()) + { + frame_count++; + gui->draw(); + graphics->updateScreen(); + mFpsManager.limitFps(config.fpsLimit); + } + else + { + mFpsManager.limitFps(10); + } - case STATE_WORLD_SELECT_ATTEMPT: - logger->log("State: WORLD SELECT ATTEMPT"); - mCurrentDialog = new ConnectionDialog( - _("Entering game world"), STATE_WORLD_SELECT); - break; + // TODO: Add connect timeouts + if (mState == STATE_CONNECT_GAME && + Net::getGameHandler()->isConnected()) + { + Net::getLoginHandler()->disconnect(); + } + else if (mState == STATE_CONNECT_SERVER && + mOldState == STATE_CONNECT_SERVER && + Net::getLoginHandler()->isConnected()) + { + mState = STATE_LOGIN; + } + else if (mState == STATE_WORLD_SELECT && mOldState == STATE_UPDATE) + { + if (Net::getLoginHandler()->getWorlds().size() < 2) + { + mState = STATE_LOGIN; + } + } + else if (mOldState == STATE_START || + (mOldState == STATE_GAME && mState != STATE_GAME)) + { + auto *top = static_cast<gcn::Container*>(gui->getTop()); + + mDesktop = new Desktop; + top->add(mDesktop); + mSetupButton = new Button("", "Setup", this); + mSetupButton->setButtonPopupText(_("Setup")); + mSetupButton->setButtonIcon("button-icon-setup.png"); + mSetupButton->setPosition(top->getWidth() - mSetupButton->getWidth() + - 3, 3); + top->add(mSetupButton); + + mDesktop->setSize(graphics->getWidth(), graphics->getHeight()); + } - case STATE_UPDATE: - logger->log("State: UPDATE"); + if (mState == STATE_SWITCH_LOGIN && mOldState == STATE_GAME) + { + Net::getGameHandler()->disconnect(); + } - if (mOptions.skipUpdate) - { - mState = STATE_LOAD_DATA; - } - else if (initUpdatesDir()) - { - mCurrentDialog = new UpdaterWindow(mUpdateHost, - mLocalDataDir + "/" + mUpdatesDir, - mOptions.dataPath.empty()); - } - break; + if (mState != mOldState) + { + { + Event event(Event::StateChange); + event.setInt("oldState", mOldState); + event.setInt("newState", mState); + event.trigger(Event::ClientChannel); + } - case STATE_LOAD_DATA: - logger->log("State: LOAD DATA"); + if (mOldState == STATE_GAME) + { + delete mGame; + mGame = nullptr; + } - // If another data path has been set, - // we don't load any other files... - if (mOptions.dataPath.empty()) - { - // Add customdata directory - ResourceManager::searchAndAddArchives( - "customdata/", - "zip", - false); - } + mOldState = mState; - // TODO remove this as soon as inventoryhandler stops using this event - Event::trigger(Event::ClientChannel, Event::LoadingDatabases); + // Get rid of the dialog of the previous state + if (mCurrentDialog) + { + delete mCurrentDialog; + mCurrentDialog = nullptr; + } + // State has changed, while the quitDialog was active, it might + // not be correct anymore + if (mQuitDialog) + mQuitDialog->scheduleDelete(); - // Load XML databases - CharDB::load(); + switch (mState) + { + case STATE_CHOOSE_SERVER: + Log::info("State: CHOOSE SERVER"); - delete itemDb; + // Don't allow an alpha opacity + // lower than the default value + gui->getTheme()->setMinimumOpacity(0.8f); - switch (Net::getNetworkType()) - { - case ServerType::TmwAthena: - itemDb = new TmwAthena::TaItemDB; - break; - case ServerType::ManaServ: - itemDb = new ManaServ::ManaServItemDB; - break; - default: - // Nothing - itemDb = nullptr; - break; - } - assert(itemDb); + mCurrentDialog = new ServerDialog(&mCurrentServer, + mConfigDir); + break; - // load settings.xml - SettingsManager::load(); + case STATE_CONNECT_SERVER: + Log::info("State: CONNECT SERVER"); - ActorSprite::load(); + Net::connectToServer(mCurrentServer); - mDesktop->reloadWallpaper(); + mCurrentDialog = new ConnectionDialog( + _("Connecting to server"), STATE_SWITCH_SERVER); + break; - mState = STATE_GET_CHARACTERS; - break; + case STATE_LOGIN: + Log::info("State: LOGIN"); + // Don't allow an alpha opacity + // lower than the default value + gui->getTheme()->setMinimumOpacity(0.8f); - case STATE_GET_CHARACTERS: - logger->log("State: GET CHARACTERS"); - Net::getCharHandler()->requestCharacters(); - mCurrentDialog = new ConnectionDialog( - _("Requesting characters"), - STATE_SWITCH_SERVER); - break; + if (mOptions.username.empty() || mOptions.password.empty()) + { + mCurrentDialog = new LoginDialog(&loginData); + } + else + { + mState = STATE_LOGIN_ATTEMPT; + // Clear the password so that when login fails, the + // dialog will show up next time. + mOptions.password.clear(); + } + break; - case STATE_CHAR_SELECT: - logger->log("State: CHAR SELECT"); - // Don't allow an alpha opacity - // lower than the default value - gui->getTheme()->setMinimumOpacity(0.8f); + case STATE_LOGIN_ATTEMPT: + Log::info("State: LOGIN ATTEMPT"); + accountLogin(&loginData); + mCurrentDialog = new ConnectionDialog( + _("Logging in"), STATE_SWITCH_SERVER); + break; - mCurrentDialog = new CharSelectDialog(&loginData); + case STATE_WORLD_SELECT: + Log::info("State: WORLD SELECT"); + { + Worlds worlds = Net::getLoginHandler()->getWorlds(); - if (!((CharSelectDialog*) mCurrentDialog)->selectByName( - mOptions.character, CharSelectDialog::Choose)) + if (worlds.empty()) { - ((CharSelectDialog*) mCurrentDialog)->selectByName( - config.lastCharacter, - mOptions.chooseDefault ? - CharSelectDialog::Choose : - CharSelectDialog::Focus); + // Trust that the netcode knows what it's doing + mState = STATE_UPDATE; } + else if (worlds.size() == 1 || mOptions.chooseDefault) + { + Net::getLoginHandler()->chooseServer(0); + mState = STATE_UPDATE; + } + else + { + mCurrentDialog = new WorldSelectDialog(std::move(worlds)); + } + } + break; - // Choosing character on the command line should work only - // once, clear it so that 'switch character' works. - mOptions.character.clear(); - mOptions.chooseDefault = false; - - break; - - case STATE_CONNECT_GAME: - logger->log("State: CONNECT GAME"); - - Net::getGameHandler()->connect(); - mCurrentDialog = new ConnectionDialog( - _("Connecting to the game server"), - Net::getNetworkType() == ServerType::TmwAthena ? - STATE_CHOOSE_SERVER : STATE_SWITCH_CHARACTER); - break; - - case STATE_CHANGE_MAP: - logger->log("State: CHANGE_MAP"); - - Net::getGameHandler()->connect(); - mCurrentDialog = new ConnectionDialog( - _("Changing game servers"), - STATE_SWITCH_CHARACTER); - break; - - case STATE_GAME: - logger->log("Memorizing selected character %s", - local_player->getName().c_str()); - config.lastCharacter = local_player->getName(); - - // Fade out logon-music here too to give the desired effect - // of "flowing" into the game. - sound.fadeOutMusic(1000); - - // Allow any alpha opacity - gui->getTheme()->setMinimumOpacity(0.0f); - - delete mSetupButton; - delete mDesktop; - mSetupButton = nullptr; - mDesktop = nullptr; - - mCurrentDialog = nullptr; - - logger->log("State: GAME"); - mGame = new Game; - break; - - case STATE_LOGIN_ERROR: - logger->log("State: LOGIN ERROR"); - showErrorDialog(errorMessage, STATE_LOGIN); - break; - - case STATE_ACCOUNTCHANGE_ERROR: - logger->log("State: ACCOUNT CHANGE ERROR"); - showErrorDialog(errorMessage, STATE_CHAR_SELECT); - break; + case STATE_WORLD_SELECT_ATTEMPT: + Log::info("State: WORLD SELECT ATTEMPT"); + mCurrentDialog = new ConnectionDialog( + _("Entering game world"), STATE_WORLD_SELECT); + break; - case STATE_REGISTER_PREP: - logger->log("State: REGISTER_PREP"); - Net::getLoginHandler()->getRegistrationDetails(); - mCurrentDialog = new ConnectionDialog( - _("Requesting registration details"), STATE_LOGIN); - break; + case STATE_UPDATE: + Log::info("State: UPDATE"); - case STATE_REGISTER: - logger->log("State: REGISTER"); - mCurrentDialog = new RegisterDialog(&loginData); - break; + if (mOptions.skipUpdate) + { + mState = STATE_LOAD_DATA; + } + else if (initUpdatesDir()) + { + mCurrentDialog = new UpdaterWindow(mUpdateHost, + mLocalDataDir + "/" + mUpdatesDir, + mOptions.dataPath.empty()); + } + break; - case STATE_REGISTER_ATTEMPT: - logger->log("Username is %s", loginData.username.c_str()); - Net::getLoginHandler()->registerAccount(&loginData); - loginData.password.clear(); - break; + case STATE_LOAD_DATA: + Log::info("State: LOAD DATA"); - case STATE_CHANGEPASSWORD: - logger->log("State: CHANGE PASSWORD"); - mCurrentDialog = new ChangePasswordDialog(&loginData); - break; + // If another data path has been set, + // we don't load any other files... + if (mOptions.dataPath.empty()) + { + // Add customdata directory + ResourceManager::searchAndAddArchives( + "customdata/", + "zip", + false); + } - case STATE_CHANGEPASSWORD_ATTEMPT: - logger->log("State: CHANGE PASSWORD ATTEMPT"); - Net::getLoginHandler()->changePassword(loginData.username, - loginData.password, - loginData.newPassword); - break; + // TODO remove this as soon as inventoryhandler stops using this event + Event::trigger(Event::ClientChannel, Event::LoadingDatabases); - case STATE_CHANGEPASSWORD_SUCCESS: - logger->log("State: CHANGE PASSWORD SUCCESS"); - showOkDialog(_("Password Change"), - _("Password changed successfully!"), - STATE_CHAR_SELECT); - loginData.password.clear(); - loginData.newPassword.clear(); - break; + // Load XML databases + CharDB::load(); - case STATE_CHANGEEMAIL: - logger->log("State: CHANGE EMAIL"); - mCurrentDialog = new ChangeEmailDialog(&loginData); - break; + delete itemDb; - case STATE_CHANGEEMAIL_ATTEMPT: - logger->log("State: CHANGE EMAIL ATTEMPT"); - Net::getLoginHandler()->changeEmail(loginData.email); - break; + switch (Net::getNetworkType()) + { + case ServerType::TmwAthena: + itemDb = new TmwAthena::TaItemDB; + break; + case ServerType::ManaServ: + itemDb = new ManaServ::ManaServItemDB; + break; + default: + // Nothing + itemDb = nullptr; + break; + } + assert(itemDb); - case STATE_CHANGEEMAIL_SUCCESS: - logger->log("State: CHANGE EMAIL SUCCESS"); - showOkDialog(_("Email Change"), - _("Email changed successfully!"), - STATE_CHAR_SELECT); - break; + // load settings.xml + SettingsManager::load(); - case STATE_UNREGISTER: - logger->log("State: UNREGISTER"); - mCurrentDialog = new UnRegisterDialog(&loginData); - break; + ActorSprite::load(); - case STATE_UNREGISTER_ATTEMPT: - logger->log("State: UNREGISTER ATTEMPT"); - Net::getLoginHandler()->unregisterAccount( - loginData.username, loginData.password); - break; + mDesktop->reloadWallpaper(); - case STATE_UNREGISTER_SUCCESS: - logger->log("State: UNREGISTER SUCCESS"); - Net::getLoginHandler()->disconnect(); + mState = STATE_GET_CHARACTERS; + break; - showOkDialog(_("Unregister Successful"), - _("Farewell, come back any time..."), - STATE_CHOOSE_SERVER); - loginData.clear(); - break; + case STATE_GET_CHARACTERS: + Log::info("State: GET CHARACTERS"); + Net::getCharHandler()->requestCharacters(); + mCurrentDialog = new ConnectionDialog( + _("Requesting characters"), + STATE_SWITCH_SERVER); + break; - case STATE_SWITCH_SERVER: - logger->log("State: SWITCH SERVER"); + case STATE_CHAR_SELECT: + Log::info("State: CHAR SELECT"); + // Don't allow an alpha opacity + // lower than the default value + gui->getTheme()->setMinimumOpacity(0.8f); - Net::getLoginHandler()->disconnect(); - Net::getGameHandler()->disconnect(); + mCurrentDialog = new CharSelectDialog(&loginData); - mCurrentServer.hostname.clear(); - mState = STATE_CHOOSE_SERVER; - break; + if (!((CharSelectDialog*) mCurrentDialog)->selectByName( + mOptions.character, CharSelectDialog::Choose)) + { + ((CharSelectDialog*) mCurrentDialog)->selectByName( + config.lastCharacter, + mOptions.chooseDefault ? + CharSelectDialog::Choose : + CharSelectDialog::Focus); + } - case STATE_SWITCH_LOGIN: - logger->log("State: SWITCH LOGIN"); + // Choosing character on the command line should work only + // once, clear it so that 'switch character' works. + mOptions.character.clear(); + mOptions.chooseDefault = false; - Net::getLoginHandler()->disconnect(); + break; - mState = STATE_CONNECT_SERVER; - break; + case STATE_CONNECT_GAME: + Log::info("State: CONNECT GAME"); - case STATE_SWITCH_CHARACTER: - logger->log("State: SWITCH CHARACTER"); + Net::getGameHandler()->connect(); + mCurrentDialog = new ConnectionDialog( + _("Connecting to the game server"), + Net::getNetworkType() == ServerType::TmwAthena ? + STATE_CHOOSE_SERVER : STATE_SWITCH_CHARACTER); + break; - // Done with game - Net::getGameHandler()->disconnect(); + case STATE_CHANGE_MAP: + Log::info("State: CHANGE_MAP"); - mState = STATE_GET_CHARACTERS; - break; + Net::getGameHandler()->connect(); + mCurrentDialog = new ConnectionDialog( + _("Changing game servers"), + STATE_SWITCH_CHARACTER); + break; - case STATE_LOGOUT_ATTEMPT: - logger->log("State: LOGOUT ATTEMPT"); - // TODO - break; + case STATE_GAME: + Log::info("Memorizing selected character %s", + local_player->getName().c_str()); + config.lastCharacter = local_player->getName(); - case STATE_WAIT: - logger->log("State: WAIT"); - break; + // Fade out logon-music here too to give the desired effect + // of "flowing" into the game. + sound.fadeOutMusic(1000); - case STATE_EXIT: - logger->log("State: EXIT"); - break; + // Allow any alpha opacity + gui->getTheme()->setMinimumOpacity(0.0f); - case STATE_FORCE_QUIT: - logger->log("State: FORCE QUIT"); - mState = STATE_EXIT; - break; + delete mSetupButton; + delete mDesktop; + mSetupButton = nullptr; + mDesktop = nullptr; - case STATE_ERROR: - logger->log("State: ERROR"); - logger->log("Error: %s", errorMessage.c_str()); - showErrorDialog(errorMessage, STATE_CHOOSE_SERVER); - Net::getGameHandler()->disconnect(); - break; + mCurrentDialog = nullptr; - default: - mState = STATE_FORCE_QUIT; - break; - } + Log::info("State: GAME"); + mGame = new Game; + break; + + case STATE_LOGIN_ERROR: + Log::info("State: LOGIN ERROR"); + showErrorDialog(errorMessage, STATE_LOGIN); + break; + + case STATE_ACCOUNTCHANGE_ERROR: + Log::info("State: ACCOUNT CHANGE ERROR"); + showErrorDialog(errorMessage, STATE_CHAR_SELECT); + break; + + case STATE_REGISTER_PREP: + Log::info("State: REGISTER_PREP"); + Net::getLoginHandler()->getRegistrationDetails(); + mCurrentDialog = new ConnectionDialog( + _("Requesting registration details"), STATE_LOGIN); + break; + + case STATE_REGISTER: + Log::info("State: REGISTER"); + mCurrentDialog = new RegisterDialog(&loginData); + break; + + case STATE_REGISTER_ATTEMPT: + Log::info("Username is %s", loginData.username.c_str()); + Net::getLoginHandler()->registerAccount(&loginData); + loginData.password.clear(); + break; + + case STATE_CHANGEPASSWORD: + Log::info("State: CHANGE PASSWORD"); + mCurrentDialog = new ChangePasswordDialog(&loginData); + break; + + case STATE_CHANGEPASSWORD_ATTEMPT: + Log::info("State: CHANGE PASSWORD ATTEMPT"); + Net::getLoginHandler()->changePassword(loginData.username, + loginData.password, + loginData.newPassword); + break; + + case STATE_CHANGEPASSWORD_SUCCESS: + Log::info("State: CHANGE PASSWORD SUCCESS"); + showOkDialog(_("Password Change"), + _("Password changed successfully!"), + STATE_CHAR_SELECT); + loginData.password.clear(); + loginData.newPassword.clear(); + break; + + case STATE_CHANGEEMAIL: + Log::info("State: CHANGE EMAIL"); + mCurrentDialog = new ChangeEmailDialog(&loginData); + break; + + case STATE_CHANGEEMAIL_ATTEMPT: + Log::info("State: CHANGE EMAIL ATTEMPT"); + Net::getLoginHandler()->changeEmail(loginData.email); + break; + + case STATE_CHANGEEMAIL_SUCCESS: + Log::info("State: CHANGE EMAIL SUCCESS"); + showOkDialog(_("Email Change"), + _("Email changed successfully!"), + STATE_CHAR_SELECT); + break; + + case STATE_UNREGISTER: + Log::info("State: UNREGISTER"); + mCurrentDialog = new UnRegisterDialog(&loginData); + break; + + case STATE_UNREGISTER_ATTEMPT: + Log::info("State: UNREGISTER ATTEMPT"); + Net::getLoginHandler()->unregisterAccount( + loginData.username, loginData.password); + break; + + case STATE_UNREGISTER_SUCCESS: + Log::info("State: UNREGISTER SUCCESS"); + Net::getLoginHandler()->disconnect(); + + showOkDialog(_("Unregister Successful"), + _("Farewell, come back any time..."), + STATE_CHOOSE_SERVER); + loginData.clear(); + break; + + case STATE_SWITCH_SERVER: + Log::info("State: SWITCH SERVER"); + + Net::getLoginHandler()->disconnect(); + Net::getGameHandler()->disconnect(); + + mCurrentServer.hostname.clear(); + mState = STATE_CHOOSE_SERVER; + break; + + case STATE_SWITCH_LOGIN: + Log::info("State: SWITCH LOGIN"); + + Net::getLoginHandler()->disconnect(); + + mState = STATE_CONNECT_SERVER; + break; + + case STATE_SWITCH_CHARACTER: + Log::info("State: SWITCH CHARACTER"); + + // Done with game + Net::getGameHandler()->disconnect(); + + mState = STATE_GET_CHARACTERS; + break; + + case STATE_LOGOUT_ATTEMPT: + Log::info("State: LOGOUT ATTEMPT"); + // TODO + break; + + case STATE_WAIT: + Log::info("State: WAIT"); + break; + + case STATE_EXIT: + Log::info("State: EXIT"); + break; + + case STATE_FORCE_QUIT: + Log::info("State: FORCE QUIT"); + mState = STATE_EXIT; + break; + + case STATE_ERROR: + Log::info("State: ERROR"); + Log::error("%s", errorMessage.c_str()); + showErrorDialog(errorMessage, STATE_CHOOSE_SERVER); + Net::getGameHandler()->disconnect(); + break; + + default: + mState = STATE_FORCE_QUIT; + break; } } - - Net::unload(); - - return 0; } void Client::showOkDialog(const std::string &title, @@ -989,7 +1013,7 @@ void Client::initRootDir() Configuration portable; portable.init(portableName); - logger->log("Portable file: %s", portableName.c_str()); + Log::info("Portable file: %s", portableName.c_str()); if (mOptions.localDataDir.empty()) { @@ -997,8 +1021,8 @@ void Client::initRootDir() if (!dir.empty()) { mOptions.localDataDir = mRootDir + dir; - logger->log("Portable data dir: %s", - mOptions.localDataDir.c_str()); + Log::info("Portable data dir: %s", + mOptions.localDataDir.c_str()); } } @@ -1008,8 +1032,8 @@ void Client::initRootDir() if (!dir.empty()) { mOptions.configDir = mRootDir + dir; - logger->log("Portable config dir: %s", - mOptions.configDir.c_str()); + Log::info("Portable config dir: %s", + mOptions.configDir.c_str()); } } @@ -1019,8 +1043,8 @@ void Client::initRootDir() if (!dir.empty()) { mOptions.screenshotDir = mRootDir + dir; - logger->log("Portable screenshot dir: %s", - mOptions.screenshotDir.c_str()); + Log::info("Portable screenshot dir: %s", + mOptions.screenshotDir.c_str()); } } } @@ -1052,7 +1076,7 @@ void Client::initHomeDir() if (mkdir_r(mLocalDataDir.c_str())) { - logger->error(strprintf(_("%s doesn't exist and can't be created! " + Log::critical(strprintf(_("%s doesn't exist and can't be created! " "Exiting."), mLocalDataDir.c_str())); } @@ -1075,7 +1099,7 @@ void Client::initHomeDir() if (mkdir_r(mConfigDir.c_str())) { - logger->error(strprintf(_("%s doesn't exist and can't be created! " + Log::critical(strprintf(_("%s doesn't exist and can't be created! " "Exiting."), mConfigDir.c_str())); } } @@ -1094,7 +1118,7 @@ void Client::initConfiguration() if (doc.rootNode() && doc.rootNode().name() == "configuration") deserialize(doc.rootNode(), config); else - logger->log("Couldn't read configuration file: %s", configPath.c_str()); + Log::info("Couldn't read configuration file: %s", configPath.c_str()); } /** @@ -1117,7 +1141,7 @@ bool Client::initUpdatesDir() if (mUpdateHost.empty()) { - logger->log("No update host provided"); + Log::info("No update host provided"); mUpdatesDir.clear(); mState = STATE_LOAD_DATA; return false; @@ -1125,8 +1149,8 @@ bool Client::initUpdatesDir() mUpdatesDir = "updates/" + getDirectoryFromURL(mUpdateHost); - logger->log("Update host: %s", mUpdateHost.c_str()); - logger->log("Updates dir: %s", mUpdatesDir.c_str()); + Log::info("Update host: %s", mUpdateHost.c_str()); + Log::info("Updates dir: %s", mUpdatesDir.c_str()); // Verify that the updates directory exists. Create if necessary. if (!FS::isDirectory(mUpdatesDir)) @@ -1146,16 +1170,16 @@ bool Client::initUpdatesDir() if (!CreateDirectory(newDir.c_str(), 0) && GetLastError() != ERROR_ALREADY_EXISTS) { - logger->log("Error: %s can't be made, but doesn't exist!", - newDir.c_str()); + Log::error("%s can't be made, but doesn't exist!", + newDir.c_str()); errorMessage = strprintf(_("Error creating updates directory!\n(%s)"), newDir.c_str()); mState = STATE_ERROR; } #else - logger->log("Error: %s/%s can't be made, but doesn't exist!", - mLocalDataDir.c_str(), mUpdatesDir.c_str()); + Log::error("%s/%s can't be made, but doesn't exist!", + mLocalDataDir.c_str(), mUpdatesDir.c_str()); errorMessage = strprintf(_("Error creating updates directory!\n(%s/%s)"), mLocalDataDir.c_str(), mUpdatesDir.c_str()); @@ -1201,7 +1225,7 @@ void Client::initScreenshotDir() void Client::accountLogin(LoginData *loginData) { - logger->log("Username is %s", loginData->username.c_str()); + Log::info("Username is %s", loginData->username.c_str()); // Send login infos if (loginData->registerLogin) @@ -1224,10 +1248,6 @@ void Client::handleWindowSizeChanged(int width, int height) // Store the new size in the configuration. config.screenWidth = width; config.screenHeight = height; - - mVideo.windowSizeChanged(width, height); - - checkGraphicsSize(); } void Client::checkGraphicsSize() diff --git a/src/client.h b/src/client.h index a3e9c572..b9e16af4 100644 --- a/src/client.h +++ b/src/client.h @@ -150,6 +150,8 @@ public: int exec(); + void update(); + /** * Pops up an OkDialog with the given \a title and \a message, and * switches to the given \a state when Ok is pressed. @@ -236,4 +238,27 @@ private: SDL_TimerID mSecondsCounterId = 0; FpsManager mFpsManager; + +#if defined(_WIN32) || defined(__APPLE__) + /** + * This class triggers an update on the window expose event, which allows + * the application to draw while Windows is in a modal move/resize loop + * as well as while resizing on macOS. + */ + class ExposeEventWatcher + { + public: + ExposeEventWatcher() { SDL_AddEventWatch(&watch, nullptr); } + ~ExposeEventWatcher() { SDL_DelEventWatch(&watch, nullptr); } + + static int watch(void *, SDL_Event *event) + { + if (event->type == SDL_WINDOWEVENT && event->window.event == SDL_WINDOWEVENT_EXPOSED) + Client::instance()->update(); + return 0; + } + }; + + ExposeEventWatcher mExposeEventWatcher; +#endif }; diff --git a/src/configuration.cpp b/src/configuration.cpp index b27fbe31..e220f4c6 100644 --- a/src/configuration.cpp +++ b/src/configuration.cpp @@ -107,9 +107,9 @@ VariableData *Configuration::getDefault(const std::string &key, return itdef->second; } - logger->log("%s: No value in registry for key %s", - mConfigPath.c_str(), - key.c_str()); + Log::info("%s: No value in registry for key %s", + mConfigPath.c_str(), + key.c_str()); } return nullptr; @@ -214,13 +214,13 @@ void Configuration::init(const std::string &filename, bool useResManager) if (!rootNode) { - logger->log("Couldn't open configuration file: %s", filename.c_str()); + Log::info("Couldn't open configuration file: %s", filename.c_str()); return; } if (rootNode.name() != "configuration") { - logger->log("Warning: No configuration file (%s)", filename.c_str()); + Log::warn("No configuration file (%s)", filename.c_str()); return; } @@ -351,6 +351,7 @@ void serdeOptions(T option) option("showgender", &Config::showGender); option("showMonstersTakedDamage", &Config::showMonstersTakedDamage); option("showWarps", &Config::showWarps); + option("hideCompletedQuests", &Config::hideCompletedQuests); option("particleMaxCount", &Config::particleMaxCount); option("particleFastPhysics", &Config::particleFastPhysics); option("particleEmitterSkip", &Config::particleEmitterSkip); diff --git a/src/configuration.h b/src/configuration.h index 3ed3c77e..9e00cb74 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -181,6 +181,7 @@ struct Config bool showGender = false; bool showMonstersTakedDamage = false; bool showWarps = true; + bool hideCompletedQuests = false; int particleMaxCount = 3000; int particleFastPhysics = 0; int particleEmitterSkip = 1; diff --git a/src/effectmanager.cpp b/src/effectmanager.cpp index 32280555..d1b3a037 100644 --- a/src/effectmanager.cpp +++ b/src/effectmanager.cpp @@ -38,13 +38,13 @@ EffectManager::EffectManager() // Handle old naming until the 0.5.x versions are obsolete. if (!root || root.name() != "being-effects") { - logger->log("Error loading being effects file: effects.xml"); + Log::info("Error loading being effects file: effects.xml"); return; } } else { - logger->log("Effects are now loading"); + Log::info("Effects are now loading"); } for (auto node : root.children()) @@ -67,7 +67,7 @@ bool EffectManager::trigger(int id, Being *being, int rotation) auto it = mEffects.find(id); if (it == mEffects.end()) { - logger->log("EffectManager::trigger: effect %d not found", id); + Log::warn("EffectManager::trigger: effect %d not found", id); return false; } @@ -90,7 +90,7 @@ bool EffectManager::trigger(int id, int x, int y, int rotation) auto it = mEffects.find(id); if (it == mEffects.end()) { - logger->log("EffectManager::trigger: effect %d not found", id); + Log::warn("EffectManager::trigger: effect %d not found", id); return false; } diff --git a/src/event.h b/src/event.h index d3fdede9..3cbd9123 100644 --- a/src/event.h +++ b/src/event.h @@ -53,7 +53,8 @@ public: ItemChannel, NoticesChannel, NpcChannel, - StorageChannel + StorageChannel, + QuestsChannel }; enum Type @@ -99,7 +100,8 @@ public: UpdateStat, UpdateStatusEffect, Whisper, - WhisperError + WhisperError, + QuestVarsChanged, }; /** diff --git a/src/game.cpp b/src/game.cpp index a6764fcf..7e2496a1 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -21,15 +21,15 @@ #include "game.h" -#include "actorspritemanager.h" #include "actorsprite.h" +#include "actorspritemanager.h" #include "channelmanager.h" #include "client.h" #include "commandhandler.h" #include "configuration.h" #include "effectmanager.h" -#include "event.h" #include "emoteshortcut.h" +#include "event.h" #include "graphics.h" #include "itemshortcut.h" #include "joystick.h" @@ -41,24 +41,24 @@ #include "playerrelations.h" #include "sound.h" +#include "gui/abilitieswindow.h" #include "gui/chatwindow.h" #include "gui/debugwindow.h" #include "gui/equipmentwindow.h" #include "gui/gui.h" #include "gui/helpwindow.h" #include "gui/inventorywindow.h" -#include "gui/shortcutwindow.h" #include "gui/minimap.h" #include "gui/ministatuswindow.h" #include "gui/npcdialog.h" #include "gui/okdialog.h" #include "gui/outfitwindow.h" +#include "gui/questswindow.h" #include "gui/quitdialog.h" -#include "gui/sdlinput.h" #include "gui/setup.h" -#include "gui/socialwindow.h" -#include "gui/abilitieswindow.h" +#include "gui/shortcutwindow.h" #include "gui/skilldialog.h" +#include "gui/socialwindow.h" #include "gui/statuswindow.h" #include "gui/textdialog.h" #include "gui/tradewindow.h" @@ -79,7 +79,6 @@ #include "utils/gettext.h" #include "utils/mkdir.h" -#include <guichan/exception.hpp> #include <guichan/focushandler.hpp> #include <fstream> @@ -96,6 +95,7 @@ StatusWindow *statusWindow; MiniStatusWindow *miniStatusWindow; InventoryWindow *inventoryWindow; SkillDialog *skillDialog; +QuestsWindow *questsWindow; Minimap *minimap; EquipmentWindow *equipmentWindow; TradeWindow *tradeWindow; @@ -152,6 +152,7 @@ static void createGuiWindows() statusWindow = new StatusWindow; inventoryWindow = new InventoryWindow(PlayerInfo::getInventory()); skillDialog = new SkillDialog; + questsWindow = new QuestsWindow; helpWindow = new HelpWindow; debugWindow = new DebugWindow; itemShortcutWindow = new ShortcutWindow("ItemShortcut", @@ -184,6 +185,7 @@ static void destroyGuiWindows() del_0(miniStatusWindow) del_0(inventoryWindow) del_0(skillDialog) + del_0(questsWindow) del_0(minimap) del_0(equipmentWindow) del_0(tradeWindow) @@ -287,7 +289,7 @@ static bool saveScreenshot() if (!screenshot) { serverNotice(_("Could not take screenshot!")); - logger->log("Error: could not take screenshot."); + Log::error("Could not take screenshot."); return false; } @@ -300,9 +302,9 @@ static bool saveScreenshot() if (mkdir_r(screenshotDirectory.c_str()) != 0) { - logger->log("Directory %s doesn't exist and can't be created! " - "Setting screenshot directory to home.", - screenshotDirectory.c_str()); + Log::info("Directory %s doesn't exist and can't be created! " + "Setting screenshot directory to home.", + screenshotDirectory.c_str()); screenshotDirectory = FS::getUserDir(); } @@ -324,13 +326,21 @@ static bool saveScreenshot() if (success) { + std::string screenshotLink; +#if SDL_VERSION_ATLEAST(2, 0, 14) + screenshotLink = strprintf("@@screenshot:%s|%s@@", + filenameSuffix.str().c_str(), + filenameSuffix.str().c_str()); +#else + screenshotLink = filenameSuffix.str(); +#endif serverNotice(strprintf(_("Screenshot saved as %s"), - filenameSuffix.str().c_str())); + screenshotLink.c_str())); } else { serverNotice(_("Saving screenshot failed!")); - logger->log("Error: could not save screenshot."); + Log::error("Could not save screenshot."); } SDL_FreeSurface(screenshot); @@ -387,516 +397,457 @@ static void handleItemPickUp() } /** - * The huge input handling method. + * Handles an SDL_KEYDOWN event and returns whether it was consumed. */ -void Game::handleInput() +bool Game::keyDownEvent(SDL_KeyboardEvent &event) { - if (joystick) - joystick->update(); + gcn::Window *requestedWindow = nullptr; + + // send straight to gui for certain windows + if (quitDialog || TextDialog::isActive() || + PlayerInfo::getNPCPostCount() > 0) + { + return false; + } - // Events - SDL_Event event; - while (SDL_PollEvent(&event)) + if (keyboard.isKeyActive(KeyboardConfig::KEY_EMOTE)) { - bool used = false; + int emotion = keyboard.getKeyEmoteOffset(event.keysym.sym); + if (emotion != -1) + { + emoteShortcut->useEmote(emotion); + return true; + } + } - if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) + if (!chatWindow->isInputFocused() + && !gui->getFocusHandler()->getModalFocused()) + { + NpcDialog *dialog = NpcDialog::getActive(); + if (keyboard.isKeyActive(KeyboardConfig::KEY_OK) + && (!dialog || !dialog->isTextInputFocused())) { - // Let the client deal with this one (it'll pass down from there) - Client::instance()->handleWindowSizeChanged(event.window.data1, - event.window.data2); + // Close the Browser if opened + if (helpWindow->isVisible()) + helpWindow->setVisible(false); + // Close the config window, cancelling changes if opened + else if (setupWindow->isVisible()) + setupWindow->action(gcn::ActionEvent(nullptr, "cancel")); + else if (dialog) + dialog->action(gcn::ActionEvent(nullptr, "ok")); } - // Keyboard events (for discontinuous keys) - else if (event.type == SDL_KEYDOWN) + if (keyboard.isKeyActive(KeyboardConfig::KEY_TOGGLE_CHAT)) { - gcn::Window *requestedWindow = nullptr; + if (chatWindow->requestChatFocus()) + return true; + } + if (dialog) + { + if (keyboard.isKeyActive(KeyboardConfig::KEY_MOVE_UP)) + dialog->move(1); + else if (keyboard.isKeyActive(KeyboardConfig::KEY_MOVE_DOWN)) + dialog->move(-1); + } + } - if (setupWindow->isVisible() && - keyboard.getNewKeyIndex() > KeyboardConfig::KEY_NO_VALUE) - { - keyboard.setNewKey(event.key.keysym.sym); - keyboard.callbackNewKey(); - keyboard.setNewKeyIndex(KeyboardConfig::KEY_NO_VALUE); - return; - } + if (!chatWindow->isInputFocused() || (event.keysym.mod & KMOD_ALT)) + { + if (keyboard.isKeyActive(KeyboardConfig::KEY_PREV_CHAT_TAB)) + { + chatWindow->prevTab(); + return true; + } + if (keyboard.isKeyActive(KeyboardConfig::KEY_NEXT_CHAT_TAB)) + { + chatWindow->nextTab(); + return true; + } + } - // send straight to gui for certain windows - if (quitDialog || TextDialog::isActive() || - PlayerInfo::getNPCPostCount() > 0) - { - try - { - guiInput->pushInput(event); - } - catch (gcn::Exception e) - { - const char* err = e.getMessage().c_str(); - logger->log("Warning: guichan input exception: %s", err); - } - return; - } + if (!chatWindow->isInputFocused()) + { + bool wearOutfit = false; + bool copyOutfit = false; - // Mode switch to emotes - if (keyboard.isKeyActive(KeyboardConfig::KEY_EMOTE)) - { - // Emotions - int emotion = keyboard.getKeyEmoteOffset(event.key.keysym.sym); - if (emotion != -1) - { - emoteShortcut->useEmote(emotion); - used = true; - return; - } - } - - if (!chatWindow->isInputFocused() - && !gui->getFocusHandler()->getModalFocused()) - { - NpcDialog *dialog = NpcDialog::getActive(); - if (keyboard.isKeyActive(KeyboardConfig::KEY_OK) - && (!dialog || !dialog->isTextInputFocused())) - { - // Close the Browser if opened - if (helpWindow->isVisible()) - helpWindow->setVisible(false); - // Close the config window, cancelling changes if opened - else if (setupWindow->isVisible()) - setupWindow->action(gcn::ActionEvent(nullptr, "cancel")); - else if (dialog) - dialog->action(gcn::ActionEvent(nullptr, "ok")); - } - if (keyboard.isKeyActive(KeyboardConfig::KEY_TOGGLE_CHAT)) - { - if (chatWindow->requestChatFocus()) - used = true; - } - if (dialog) - { - if (keyboard.isKeyActive(KeyboardConfig::KEY_MOVE_UP)) - dialog->move(1); - else if (keyboard.isKeyActive(KeyboardConfig::KEY_MOVE_DOWN)) - dialog->move(-1); - } - } + if (keyboard.isKeyActive(KeyboardConfig::KEY_WEAR_OUTFIT)) + wearOutfit = true; + if (keyboard.isKeyActive(KeyboardConfig::KEY_COPY_OUTFIT)) + copyOutfit = true; - if (!chatWindow->isInputFocused() || (event.key.keysym.mod & - KMOD_ALT)) + if (wearOutfit || copyOutfit) + { + int outfitNum = -1; + switch (event.keysym.sym) { - if (keyboard.isKeyActive(KeyboardConfig::KEY_PREV_CHAT_TAB)) - { - chatWindow->prevTab(); - return; - } - else if (keyboard.isKeyActive(KeyboardConfig::KEY_NEXT_CHAT_TAB)) - { - chatWindow->nextTab(); - return; - } + case SDLK_1: + case SDLK_2: + case SDLK_3: + case SDLK_4: + case SDLK_5: + case SDLK_6: + case SDLK_7: + case SDLK_8: + case SDLK_9: + outfitNum = event.keysym.sym - SDLK_1; + break; + + case SDLK_0: + outfitNum = 9; + break; + + case SDLK_MINUS: + outfitNum = 10; + break; + + case SDLK_EQUALS: + outfitNum = 11; + break; + + case SDLK_BACKSPACE: + outfitNum = 12; + break; + + case SDLK_INSERT: + outfitNum = 13; + break; + + case SDLK_HOME: + outfitNum = 14; + break; + + default: + break; } - - if (!chatWindow->isInputFocused()) + if (outfitNum >= 0) { - bool wearOutfit = false; - bool copyOutfit = false; + if (wearOutfit) + outfitWindow->wearOutfit(outfitNum); + else if (copyOutfit) + outfitWindow->copyOutfit(outfitNum); + return true; + } + } + } - if (keyboard.isKeyActive(KeyboardConfig::KEY_WEAR_OUTFIT)) - wearOutfit = true; + const int tKey = keyboard.getKeyIndex(event.keysym.sym); + switch (tKey) + { + case KeyboardConfig::KEY_SCROLL_CHAT_UP: + if (chatWindow->isVisible()) + { + chatWindow->scroll(-DEFAULT_CHAT_WINDOW_SCROLL); + return true; + } + break; + case KeyboardConfig::KEY_SCROLL_CHAT_DOWN: + if (chatWindow->isVisible()) + { + chatWindow->scroll(DEFAULT_CHAT_WINDOW_SCROLL); + return true; + } + break; + case KeyboardConfig::KEY_WINDOW_HELP: + // In-game Help + if (helpWindow->isVisible()) + { + helpWindow->setVisible(false); + } + else + { + helpWindow->loadHelp("index"); + helpWindow->requestMoveToTop(); + } + return true; - if (keyboard.isKeyActive(KeyboardConfig::KEY_COPY_OUTFIT)) - copyOutfit = true; + case KeyboardConfig::KEY_QUIT: + { + // Close possible stuck NPC dialogs. + NpcDialog *npcDialog = NpcDialog::getActive(); + if (npcDialog && npcDialog->isWaitingForTheServer()) + { + npcDialog->close(); + return true; + } - if (wearOutfit || copyOutfit) - { - int outfitNum = -1; - switch (event.key.keysym.sym) - { - case SDLK_1: - case SDLK_2: - case SDLK_3: - case SDLK_4: - case SDLK_5: - case SDLK_6: - case SDLK_7: - case SDLK_8: - case SDLK_9: - outfitNum = event.key.keysym.sym - SDLK_1; - break; - - case SDLK_0: - outfitNum = 9; - break; - - case SDLK_MINUS: - outfitNum = 10; - break; - - case SDLK_EQUALS: - outfitNum = 11; - break; - - case SDLK_BACKSPACE: - outfitNum = 12; - break; - - case SDLK_INSERT: - outfitNum = 13; - break; - - case SDLK_HOME: - outfitNum = 14; - break; - - default: - break; - } - if (outfitNum >= 0) - { - used = true; - if (wearOutfit) - outfitWindow->wearOutfit(outfitNum); - else if (copyOutfit) - outfitWindow->copyOutfit(outfitNum); - } - } - } + // Otherwise, show the quit confirmation dialog. + quitDialog = new QuitDialog(&quitDialog); + quitDialog->requestMoveToTop(); + return true; + } + default: + break; + } - const int tKey = keyboard.getKeyIndex(event.key.keysym.sym); - switch (tKey) - { - case KeyboardConfig::KEY_SCROLL_CHAT_UP: - if (chatWindow->isVisible()) - { - chatWindow->scroll(-DEFAULT_CHAT_WINDOW_SCROLL); - used = true; - } - break; - case KeyboardConfig::KEY_SCROLL_CHAT_DOWN: - if (chatWindow->isVisible()) - { - chatWindow->scroll(DEFAULT_CHAT_WINDOW_SCROLL); - used = true; - return; - } - break; - case KeyboardConfig::KEY_WINDOW_HELP: - // In-game Help - if (helpWindow->isVisible()) - helpWindow->setVisible(false); - else - { - helpWindow->loadHelp("index"); - helpWindow->requestMoveToTop(); - } - used = true; - break; - case KeyboardConfig::KEY_QUIT: - { - // Close possible stuck NPC dialogs. - NpcDialog *npcDialog = NpcDialog::getActive(); - if (npcDialog && npcDialog->isWaitingForTheServer()) - { - npcDialog->close(); - return; - } - - // Otherwise, show the quit confirmation dialog. - quitDialog = new QuitDialog(&quitDialog); - quitDialog->requestMoveToTop(); - return; - } - default: - break; - } - if (keyboard.isEnabled() && !chatWindow->isInputFocused() && - !NpcDialog::isAnyInputFocused() && !InventoryWindow::isAnyInputFocused()) + if (keyboard.isEnabled() && !chatWindow->isInputFocused() && + !NpcDialog::isAnyInputFocused() && !InventoryWindow::isAnyInputFocused()) + { + // Do not activate shortcuts if tradewindow is visible + if (!tradeWindow->isVisible() && !setupWindow->isVisible()) + { + // Checks if any item shortcut is pressed. + for (int i = KeyboardConfig::KEY_SHORTCUT_1; + i <= KeyboardConfig::KEY_SHORTCUT_12; + i++) { - // Do not activate shortcuts if tradewindow is visible - if (!tradeWindow->isVisible() && !setupWindow->isVisible()) + if (tKey == i) { - // Checks if any item shortcut is pressed. - for (int i = KeyboardConfig::KEY_SHORTCUT_1; - i <= KeyboardConfig::KEY_SHORTCUT_12; - i++) - { - if (tKey == i && !used) - { - itemShortcut->useItem( - i - KeyboardConfig::KEY_SHORTCUT_1); - break; - } - } - } - - switch (tKey) - { - case KeyboardConfig::KEY_PICKUP: - { - handleItemPickUp(); - - used = true; - } - break; - case KeyboardConfig::KEY_SIT: - // Player sit action - local_player->toggleSit(); - used = true; - break; - case KeyboardConfig::KEY_HIDE_WINDOWS: - // Hide certain windows - if (!chatWindow->isInputFocused()) - { - statusWindow->setVisible(false); - inventoryWindow->setVisible(false); - skillDialog->setVisible(false); - setupWindow->setVisible(false); - equipmentWindow->setVisible(false); - helpWindow->setVisible(false); - debugWindow->setVisible(false); - socialWindow->setVisible(false); - } - break; - case KeyboardConfig::KEY_WINDOW_STATUS: - requestedWindow = statusWindow; - break; - case KeyboardConfig::KEY_WINDOW_INVENTORY: - requestedWindow = inventoryWindow; - break; - case KeyboardConfig::KEY_WINDOW_EQUIPMENT: - requestedWindow = equipmentWindow; - break; - case KeyboardConfig::KEY_WINDOW_SKILL: - requestedWindow = skillDialog; - break; - case KeyboardConfig::KEY_WINDOW_MINIMAP: - minimap->toggle(); - break; - case KeyboardConfig::KEY_WINDOW_CHAT: - requestedWindow = chatWindow; - break; - case KeyboardConfig::KEY_WINDOW_SHORTCUT: - requestedWindow = itemShortcutWindow; - break; - case KeyboardConfig::KEY_WINDOW_SETUP: - requestedWindow = setupWindow; - break; - case KeyboardConfig::KEY_WINDOW_DEBUG: - requestedWindow = debugWindow; - break; - case KeyboardConfig::KEY_WINDOW_SOCIAL: - requestedWindow = socialWindow; - break; - case KeyboardConfig::KEY_WINDOW_EMOTE_SHORTCUT: - requestedWindow = emoteShortcutWindow; - break; - case KeyboardConfig::KEY_WINDOW_OUTFIT: - requestedWindow = outfitWindow; - break; - case KeyboardConfig::KEY_SCREENSHOT: - // Screenshot (picture, hence the p) - saveScreenshot(); - used = true; - break; - case KeyboardConfig::KEY_TRADE: - // Toggle accepting of incoming trade requests - unsigned int deflt = player_relations.getDefault(); - if (deflt & PlayerPermissions::TRADE) - { - serverNotice(_("Ignoring incoming trade requests")); - deflt &= ~PlayerPermissions::TRADE; - } - else - { - serverNotice(_("Accepting incoming trade requests")); - deflt |= PlayerPermissions::TRADE; - } - - player_relations.setDefault(deflt); - - used = true; - break; + itemShortcut->useItem( + i - KeyboardConfig::KEY_SHORTCUT_1); + return true; } } - - if (requestedWindow) - { - requestedWindow->setVisible(!requestedWindow->isVisible()); - if (requestedWindow->isVisible()) - requestedWindow->requestMoveToTop(); - used = true; - } - } - // Quit event - else if (event.type == SDL_QUIT) - { - Client::setState(STATE_EXIT); } - // Push input to GUI when not used - if (!used) + switch (tKey) + { + case KeyboardConfig::KEY_PICKUP: + handleItemPickUp(); + return true; + + case KeyboardConfig::KEY_SIT: + local_player->toggleSit(); + return true; + + case KeyboardConfig::KEY_HIDE_WINDOWS: + // Hide certain windows + statusWindow->setVisible(false); + inventoryWindow->setVisible(false); + skillDialog->setVisible(false); + questsWindow->setVisible(false); + setupWindow->setVisible(false); + equipmentWindow->setVisible(false); + helpWindow->setVisible(false); + debugWindow->setVisible(false); + socialWindow->setVisible(false); + break; + + case KeyboardConfig::KEY_WINDOW_STATUS: + requestedWindow = statusWindow; + break; + case KeyboardConfig::KEY_WINDOW_INVENTORY: + requestedWindow = inventoryWindow; + break; + case KeyboardConfig::KEY_WINDOW_EQUIPMENT: + requestedWindow = equipmentWindow; + break; + case KeyboardConfig::KEY_WINDOW_SKILL: + requestedWindow = skillDialog; + break; + case KeyboardConfig::KEY_WINDOW_QUESTS: + requestedWindow = questsWindow; + break; + case KeyboardConfig::KEY_WINDOW_MINIMAP: + minimap->toggle(); + return true; + case KeyboardConfig::KEY_WINDOW_CHAT: + requestedWindow = chatWindow; + break; + case KeyboardConfig::KEY_WINDOW_SHORTCUT: + requestedWindow = itemShortcutWindow; + break; + case KeyboardConfig::KEY_WINDOW_SETUP: + requestedWindow = setupWindow; + break; + case KeyboardConfig::KEY_WINDOW_DEBUG: + requestedWindow = debugWindow; + break; + case KeyboardConfig::KEY_WINDOW_SOCIAL: + requestedWindow = socialWindow; + break; + case KeyboardConfig::KEY_WINDOW_EMOTE_SHORTCUT: + requestedWindow = emoteShortcutWindow; + break; + case KeyboardConfig::KEY_WINDOW_OUTFIT: + requestedWindow = outfitWindow; + break; + case KeyboardConfig::KEY_SCREENSHOT: + saveScreenshot(); + return true; + + case KeyboardConfig::KEY_TRADE: { - try + // Toggle accepting of incoming trade requests + unsigned int deflt = player_relations.getDefault(); + if (deflt & PlayerPermissions::TRADE) { - guiInput->pushInput(event); + serverNotice(_("Ignoring incoming trade requests")); + deflt &= ~PlayerPermissions::TRADE; } - catch (gcn::Exception e) + else { - const char *err = e.getMessage().c_str(); - logger->log("Warning: guichan input exception: %s", err); + serverNotice(_("Accepting incoming trade requests")); + deflt |= PlayerPermissions::TRADE; } + + player_relations.setDefault(deflt); + + return true; + } + + case KeyboardConfig::KEY_TALK: + if (Being *target = local_player->getTarget()) + if (target->canTalk()) + target->talkTo(); + return true; } + } + + if (requestedWindow) + { + requestedWindow->setVisible(!requestedWindow->isVisible()); + if (requestedWindow->isVisible()) + requestedWindow->requestMoveToTop(); + return true; + } - } // End while + return false; +} + +/** + * Continuous input handling. + */ +void Game::handleInput() +{ + if (joystick) + joystick->update(); // If the user is configuring the keys then don't respond. if (!keyboard.isEnabled()) return; + if (!local_player->isAlive()) + return; + if (PlayerInfo::isTalking()) + return; + if (chatWindow->isInputFocused() || quitDialog || TextDialog::isActive()) + return; // Moving player around - if (local_player->isAlive() && !PlayerInfo::isTalking() && - !chatWindow->isInputFocused() && !quitDialog && !TextDialog::isActive()) - { - // Get the state of the keyboard keys - keyboard.refreshActiveKeys(); - // Ignore input if either "ignore" key is pressed - // Stops the character moving about if the user's window manager - // uses "ignore+arrow key" to switch virtual desktops. - if (keyboard.isKeyActive(KeyboardConfig::KEY_IGNORE_INPUT_1) || - keyboard.isKeyActive(KeyboardConfig::KEY_IGNORE_INPUT_2)) - { - return; - } + // Get the state of the keyboard keys + keyboard.refreshActiveKeys(); - unsigned char direction = 0; + // Ignore input if either "ignore" key is pressed + // Stops the character moving about if the user's window manager + // uses "ignore+arrow key" to switch virtual desktops. + if (keyboard.isKeyActive(KeyboardConfig::KEY_IGNORE_INPUT_1) || + keyboard.isKeyActive(KeyboardConfig::KEY_IGNORE_INPUT_2)) + { + return; + } - // Translate pressed keys to movement and direction - if (keyboard.isKeyActive(KeyboardConfig::KEY_MOVE_UP) || - (joystick && joystick->isUp())) - { - direction |= Being::UP; - } - else if (keyboard.isKeyActive(KeyboardConfig::KEY_MOVE_DOWN) || - (joystick && joystick->isDown())) - { - direction |= Being::DOWN; - } + unsigned char direction = 0; - if (keyboard.isKeyActive(KeyboardConfig::KEY_MOVE_LEFT) || - (joystick && joystick->isLeft())) - { - direction |= Being::LEFT; - } - else if (keyboard.isKeyActive(KeyboardConfig::KEY_MOVE_RIGHT) || - (joystick && joystick->isRight())) - { - direction |= Being::RIGHT; - } + // Translate pressed keys to movement and direction + if (keyboard.isKeyActive(KeyboardConfig::KEY_MOVE_UP) || + (joystick && joystick->isUp())) + { + direction |= Being::UP; + } + else if (keyboard.isKeyActive(KeyboardConfig::KEY_MOVE_DOWN) || + (joystick && joystick->isDown())) + { + direction |= Being::DOWN; + } - if (keyboard.isKeyActive(KeyboardConfig::KEY_EMOTE) && direction != 0) - { - if (local_player->getDirection() != direction) - { - local_player->setDirection(direction); - Net::getPlayerHandler()->setDirection(direction); - } - direction = 0; - } - else - { - local_player->setWalkingDir(direction); - } + if (keyboard.isKeyActive(KeyboardConfig::KEY_MOVE_LEFT) || + (joystick && joystick->isLeft())) + { + direction |= Being::LEFT; + } + else if (keyboard.isKeyActive(KeyboardConfig::KEY_MOVE_RIGHT) || + (joystick && joystick->isRight())) + { + direction |= Being::RIGHT; + } - // Attacking monsters - if (keyboard.isKeyActive(KeyboardConfig::KEY_ATTACK) || - (joystick && joystick->buttonPressed(0))) + if (keyboard.isKeyActive(KeyboardConfig::KEY_EMOTE) && direction != 0) + { + if (local_player->getDirection() != direction) { - if (local_player->getTarget()) - local_player->attack(local_player->getTarget(), true); + local_player->setDirection(direction); + Net::getPlayerHandler()->setDirection(direction); } + } + else + { + local_player->setWalkingDir(direction); + } - if (keyboard.isKeyActive(KeyboardConfig::KEY_TARGET_ATTACK)) - { - Being *target = local_player->getTarget(); + // Attacking monsters + if (keyboard.isKeyActive(KeyboardConfig::KEY_ATTACK) || + (joystick && joystick->buttonPressed(0))) + { + if (local_player->getTarget()) + local_player->attack(local_player->getTarget(), true); + } - bool newTarget = !keyboard.isKeyActive(KeyboardConfig::KEY_TARGET); - // A set target has highest priority - if (!target) - { - // Only auto target Monsters - target = actorSpriteManager->findNearestLivingBeing(local_player, - 20, ActorSprite::MONSTER); - } - local_player->attack(target, newTarget); - } + if (keyboard.isKeyActive(KeyboardConfig::KEY_TARGET_ATTACK)) + { + Being *target = local_player->getTarget(); - // Target the nearest player/monster/npc - if ((keyboard.isKeyActive(KeyboardConfig::KEY_TARGET_PLAYER) || - keyboard.isKeyActive(KeyboardConfig::KEY_TARGET_CLOSEST) || - keyboard.isKeyActive(KeyboardConfig::KEY_TARGET_NPC) || - (joystick && joystick->buttonPressed(3))) && - !keyboard.isKeyActive(KeyboardConfig::KEY_TARGET)) + bool newTarget = !keyboard.isKeyActive(KeyboardConfig::KEY_TARGET); + // A set target has highest priority + if (!target) { - ActorSprite::Type currentTarget = ActorSprite::UNKNOWN; - if (keyboard.isKeyActive(KeyboardConfig::KEY_TARGET_CLOSEST) || - (joystick && joystick->buttonPressed(3))) - currentTarget = ActorSprite::MONSTER; - else if (keyboard.isKeyActive(KeyboardConfig::KEY_TARGET_PLAYER)) - currentTarget = ActorSprite::PLAYER; - else if (keyboard.isKeyActive(KeyboardConfig::KEY_TARGET_NPC)) - currentTarget = ActorSprite::NPC; - - Being *target = actorSpriteManager->findNearestLivingBeing(local_player, - 20, currentTarget); - - if (target && (target != local_player->getTarget() || - currentTarget != mLastTarget)) - { - local_player->setTarget(target); - mLastTarget = currentTarget; - } - } - else - { - mLastTarget = ActorSprite::UNKNOWN; // Reset last target + // Only auto target Monsters + target = actorSpriteManager->findNearestLivingBeing(local_player, + 20, ActorSprite::MONSTER); } + local_player->attack(target, newTarget); + } - // Talk to the nearest NPC if 't' pressed - if (event.type == SDL_KEYDOWN && - keyboard.getKeyIndex(event.key.keysym.sym) == KeyboardConfig::KEY_TALK) + // Target the nearest player/monster/npc + if ((keyboard.isKeyActive(KeyboardConfig::KEY_TARGET_PLAYER) || + keyboard.isKeyActive(KeyboardConfig::KEY_TARGET_CLOSEST) || + keyboard.isKeyActive(KeyboardConfig::KEY_TARGET_NPC) || + (joystick && joystick->buttonPressed(3))) && + !keyboard.isKeyActive(KeyboardConfig::KEY_TARGET)) + { + ActorSprite::Type currentTarget = ActorSprite::UNKNOWN; + if (keyboard.isKeyActive(KeyboardConfig::KEY_TARGET_CLOSEST) || + (joystick && joystick->buttonPressed(3))) + currentTarget = ActorSprite::MONSTER; + else if (keyboard.isKeyActive(KeyboardConfig::KEY_TARGET_PLAYER)) + currentTarget = ActorSprite::PLAYER; + else if (keyboard.isKeyActive(KeyboardConfig::KEY_TARGET_NPC)) + currentTarget = ActorSprite::NPC; + + Being *target = actorSpriteManager->findNearestLivingBeing(local_player, + 20, currentTarget); + + if (target && (target != local_player->getTarget() || + currentTarget != mLastTarget)) { - Being *target = local_player->getTarget(); - - if (target) - { - if (target->canTalk()) - target->talkTo(); - } + local_player->setTarget(target); + mLastTarget = currentTarget; } + } + else + { + mLastTarget = ActorSprite::UNKNOWN; // Reset last target + } - // Stop attacking if the right key is pressed - if (!keyboard.isKeyActive(KeyboardConfig::KEY_ATTACK) - && keyboard.isKeyActive(KeyboardConfig::KEY_TARGET)) - { - local_player->stopAttack(); - } + // Stop attacking if the right key is pressed + if (!keyboard.isKeyActive(KeyboardConfig::KEY_ATTACK) + && keyboard.isKeyActive(KeyboardConfig::KEY_TARGET)) + { + local_player->stopAttack(); + } - if (joystick) + if (joystick) + { + if (joystick->buttonPressed(1)) { - if (joystick->buttonPressed(1)) - { - const int x = local_player->getTileX(); - const int y = local_player->getTileY(); - - FloorItem *item = actorSpriteManager->findItem(x, y); + const int x = local_player->getTileX(); + const int y = local_player->getTileY(); - if (item) - local_player->pickUp(item); - } - else if (joystick->buttonPressed(2)) - { - local_player->toggleSit(); - } + if (FloorItem *item = actorSpriteManager->findItem(x, y)) + local_player->pickUp(item); + } + else if (joystick->buttonPressed(2)) + { + local_player->toggleSit(); } } } @@ -931,7 +882,7 @@ void Game::changeMap(const std::string &mapPath) if (!newMap) { - logger->log("Error while loading %s", fullMap.c_str()); + Log::info("Error while loading %s", fullMap.c_str()); new OkDialog(_("Could Not Load Map"), strprintf(_("Error while loading %s"), fullMap.c_str())); } @@ -58,6 +58,8 @@ class Game */ void logic(); + bool keyDownEvent(SDL_KeyboardEvent &event); + void handleInput(); void changeMap(const std::string &mapName); diff --git a/src/graphics.cpp b/src/graphics.cpp index 5455f61a..68fc4e46 100644 --- a/src/graphics.cpp +++ b/src/graphics.cpp @@ -21,27 +21,11 @@ #include "graphics.h" -#include "resources/image.h" +#include "gui/truetypefont.h" +#include "resources/theme.h" #include <guichan/exception.hpp> -#include <utility> - -ImageRect::ImageRect(ImageRect &&r) -{ - image = std::exchange(r.image, nullptr); - top = r.top; - left = r.left; - bottom = r.bottom; - right = r.right; - fillMode = r.fillMode; -} - -ImageRect::~ImageRect() -{ - delete image; -} - void Graphics::updateSize(int width, int height, float /*scale*/) { @@ -166,7 +150,7 @@ void Graphics::drawImageRect(const ImageRect &imgRect, int x, int y, int w, int switch (imgRect.fillMode) { case FillMode::Stretch: - drawRescaledImage(imgRect.image, + drawRescaledImage(imgRect.image.get(), srcGridX[ix], srcGridY[iy], dstGridX[ix], @@ -175,7 +159,7 @@ void Graphics::drawImageRect(const ImageRect &imgRect, int x, int y, int w, int dstW, dstH); break; case FillMode::Repeat: - drawRescaledImagePattern(imgRect.image, + drawRescaledImagePattern(imgRect.image.get(), srcGridX[ix], srcGridY[iy], srcW, srcH, @@ -189,6 +173,72 @@ void Graphics::drawImageRect(const ImageRect &imgRect, int x, int y, int w, int } } +void Graphics::drawText(const std::string &text, + int x, int y, + gcn::Graphics::Alignment alignment, + const gcn::Color &color, + gcn::Font *font, + bool outline, + bool shadow, + const std::optional<gcn::Color> &outlineColor, + const std::optional<gcn::Color> &shadowColor) +{ + switch (alignment) + { + case gcn::Graphics::LEFT: + break; + case gcn::Graphics::CENTER: + x -= font->getWidth(text) / 2; + break; + case gcn::Graphics::RIGHT: + x -= font->getWidth(text); + break; + default: + throw GCN_EXCEPTION("Unknown alignment."); + } + + auto realOutlineColor = outlineColor; + auto realShadowColor = shadowColor; + + if (shadow && !realShadowColor) + { + auto sc = Theme::getThemeColor(Theme::SHADOW); + sc.a = color.a / 2; + realShadowColor = sc; + } + + if (outline && !realOutlineColor) + { + auto oc = Theme::getThemeColor(Theme::OUTLINE); + oc.a = color.a; + realOutlineColor = oc; + } + + setColor(color); + static_cast<TrueTypeFont*>(font)->drawString(graphics, text, x, y, + realOutlineColor, + realShadowColor); +} + +void Graphics::drawText(const std::string &text, + int x, + int y, + gcn::Graphics::Alignment align, + gcn::Font *font, + const TextFormat &format) +{ + drawText(text, + x, + y, + align, + format.color, + font, + format.outlineColor.has_value(), + format.shadowColor.has_value(), + format.outlineColor, + format.shadowColor); +} + void Graphics::_beginDraw() { pushClipArea(gcn::Rectangle(0, 0, mWidth, mHeight)); diff --git a/src/graphics.h b/src/graphics.h index 038b0c6b..b6508753 100644 --- a/src/graphics.h +++ b/src/graphics.h @@ -21,12 +21,17 @@ #pragma once +#include "resources/image.h" + #include <SDL.h> #include <guichan/color.hpp> #include <guichan/graphics.hpp> -class Image; +#include <memory> +#include <optional> + +struct TextFormat; enum class FillMode { @@ -35,47 +40,27 @@ enum class FillMode }; /** - * 9 images defining a rectangle. 4 corners, 4 sides and a middle area. The - * topology is as follows: + * An image reference along with the margins specifying how to render this + * image at different sizes. The margins divide the image into 9 sections as + * follows: * * <pre> - * !-----!-----------------!-----! - * ! 0 ! 1 ! 2 ! - * !-----!-----------------!-----! - * ! 3 ! 4 ! 5 ! - * !-----!-----------------!-----! - * ! 6 ! 7 ! 8 ! - * !-----!-----------------!-----! + * !------!--------------!-------! + * ! ! top ! ! + * !------!--------------!-------! + * ! left ! ! right ! + * !------!--------------!-------! + * ! ! bottom ! ! + * !------!--------------!-------! * </pre> * - * Sections 0, 2, 6 and 8 will remain as is. 1, 3, 4, 5 and 7 will be - * repeated to fit the size of the widget. + * The corner sections will remain as is. The edges and the center sections + * will be repeated or stretched to fit the target size, depending on the fill + * mode. */ -class ImageRect +struct ImageRect { -public: - enum ImagePosition - { - UPPER_LEFT = 0, - UPPER_CENTER = 1, - UPPER_RIGHT = 2, - LEFT = 3, - CENTER = 4, - RIGHT = 5, - LOWER_LEFT = 6, - LOWER_CENTER = 7, - LOWER_RIGHT = 8 - }; - - ImageRect() = default; - ImageRect(const ImageRect &) = delete; - ImageRect(ImageRect &&); - ~ImageRect(); - - ImageRect &operator=(const ImageRect &) = delete; - ImageRect &operator=(ImageRect &&r) = delete; - - Image *image = nullptr; + std::unique_ptr<Image> image; int top = 0; int left = 0; int bottom = 0; @@ -205,6 +190,25 @@ class Graphics : public gcn::Graphics drawImageRect(imgRect, area.x, area.y, area.width, area.height); } + using gcn::Graphics::drawText; + + void drawText(const std::string &text, + int x, int y, + gcn::Graphics::Alignment alignment, + const gcn::Color &color, + gcn::Font *font, + bool outline = false, + bool shadow = false, + const std::optional<gcn::Color> &outlineColor = {}, + const std::optional<gcn::Color> &shadowColor = {}); + + void drawText(const std::string &text, + int x, + int y, + gcn::Graphics::Alignment align, + gcn::Font *font, + const TextFormat &format); + /** * Updates the screen. This is done by either copying the buffer to the * screen or swapping pages. diff --git a/src/gui/abilitieswindow.cpp b/src/gui/abilitieswindow.cpp index 700fa7ff..d8122bf3 100644 --- a/src/gui/abilitieswindow.cpp +++ b/src/gui/abilitieswindow.cpp @@ -145,13 +145,13 @@ void AbilitiesWindow::draw(gcn::Graphics *graphics) void AbilitiesWindow::rebuild(const std::map<int, Ability> &abilityData) { delete_all(mEntries); - + mEntries.clear(); int vPos = 0; //vertical position of next placed element for (auto &[id, ability] : abilityData) { - logger->log("Updating ability GUI for %d", id); + Log::info("Updating ability GUI for %d", id); AbilityInfo *info = AbilityDB::get(id); if (info) @@ -166,7 +166,7 @@ void AbilitiesWindow::rebuild(const std::map<int, Ability> &abilityData) } else { - logger->log("Warning: No info available of ability %d", id); + Log::warn("No info available of ability %d", id); } } } diff --git a/src/gui/buydialog.cpp b/src/gui/buydialog.cpp index 135c2119..fb316722 100644 --- a/src/gui/buydialog.cpp +++ b/src/gui/buydialog.cpp @@ -54,7 +54,7 @@ BuyDialog::BuyDialog(int npcId): setCloseButton(true); setMinWidth(260); setMinHeight(230); - setDefaultSize(260, 230, ImageRect::CENTER); + setDefaultSize(260, 230, WindowAlignment::Center); mShopItems = new ShopItems; diff --git a/src/gui/changeemaildialog.cpp b/src/gui/changeemaildialog.cpp index ce83087b..e10a0d18 100644 --- a/src/gui/changeemaildialog.cpp +++ b/src/gui/changeemaildialog.cpp @@ -112,8 +112,8 @@ void ChangeEmailDialog::action(const gcn::ActionEvent &event) const std::string username = mLoginData->username.c_str(); const std::string newFirstEmail = mFirstEmailField->getText(); const std::string newSecondEmail = mSecondEmailField->getText(); - logger->log("ChangeEmailDialog::Email change, Username is %s", - username.c_str()); + Log::info("ChangeEmailDialog::Email change, Username is %s", + username.c_str()); std::stringstream errorMessage; int error = 0; diff --git a/src/gui/changepassworddialog.cpp b/src/gui/changepassworddialog.cpp index 437a8c90..91d7721d 100644 --- a/src/gui/changepassworddialog.cpp +++ b/src/gui/changepassworddialog.cpp @@ -94,8 +94,8 @@ void ChangePasswordDialog::action(const gcn::ActionEvent &event) const std::string oldPassword = mOldPassField->getText(); const std::string newFirstPass = mFirstPassField->getText(); const std::string newSecondPass = mSecondPassField->getText(); - logger->log("ChangePasswordDialog::Password change, Username is %s", - username.c_str()); + Log::info("ChangePasswordDialog::Password change, Username is %s", + username.c_str()); std::stringstream errorMessage; int error = 0; diff --git a/src/gui/charselectdialog.cpp b/src/gui/charselectdialog.cpp index 2485be69..1ed353dd 100644 --- a/src/gui/charselectdialog.cpp +++ b/src/gui/charselectdialog.cpp @@ -271,7 +271,7 @@ void CharSelectDialog::setCharacters(const Net::Characters &characters) if (characterSlot >= (int)mCharacterEntries.size()) { - logger->log("Warning: slot out of range: %d", character->slot); + Log::warn("Slot out of range: %d", character->slot); continue; } diff --git a/src/gui/chatwindow.cpp b/src/gui/chatwindow.cpp index d006097c..d19231ab 100644 --- a/src/gui/chatwindow.cpp +++ b/src/gui/chatwindow.cpp @@ -102,7 +102,7 @@ ChatWindow::ChatWindow(): setResizable(true); setDefaultVisible(true); setSaveVisible(true); - setDefaultSize(600, 123, ImageRect::LOWER_LEFT); + setDefaultSize(600, 123, WindowAlignment::BottomLeft); setMinWidth(150); setMinHeight(90); diff --git a/src/gui/connectiondialog.cpp b/src/gui/connectiondialog.cpp index 2ff68a15..e6435269 100644 --- a/src/gui/connectiondialog.cpp +++ b/src/gui/connectiondialog.cpp @@ -54,7 +54,7 @@ ConnectionDialog::ConnectionDialog(const std::string &text, void ConnectionDialog::action(const gcn::ActionEvent &) { - logger->log("Cancel pressed"); + Log::info("Cancel pressed"); Client::setState(mCancelState); } diff --git a/src/gui/equipmentwindow.cpp b/src/gui/equipmentwindow.cpp index b9d3b0fd..8523e7b2 100644 --- a/src/gui/equipmentwindow.cpp +++ b/src/gui/equipmentwindow.cpp @@ -63,7 +63,7 @@ EquipmentWindow::EquipmentWindow(Equipment *equipment): setCloseButton(true); setSaveVisible(true); setContentSize(175, 290); - setDefaultSize(getWidth(), getHeight(), ImageRect::CENTER); + setDefaultSize(getWidth(), getHeight(), WindowAlignment::Center); loadWindowState(); mUnequip = new Button(_("Unequip"), "unequip", this); diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 0c3d78eb..768aeb2b 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -71,7 +71,7 @@ Gui::Gui(Graphics *graphics, const std::string &themePath) setTheme(themeIt != mAvailableThemes.end() ? *themeIt : mAvailableThemes.front()); - logger->log("Initializing GUI..."); + Log::info("Initializing GUI..."); // Set graphics setGraphics(graphics); @@ -106,8 +106,8 @@ Gui::Gui(Graphics *graphics, const std::string &themePath) } catch (gcn::Exception e) { - logger->error(std::string("Unable to load '") + fontFile + - std::string("': ") + e.getMessage()); + Log::critical(std::string("Unable to load '") + fontFile + + "': " + e.getMessage()); } // Set bold font @@ -119,8 +119,8 @@ Gui::Gui(Graphics *graphics, const std::string &themePath) } catch (gcn::Exception e) { - logger->error(std::string("Unable to load '") + fontFile + - std::string("': ") + e.getMessage()); + Log::critical(std::string("Unable to load '") + fontFile + + "': " + e.getMessage()); } // Set mono font @@ -132,8 +132,8 @@ Gui::Gui(Graphics *graphics, const std::string &themePath) } catch (gcn::Exception e) { - logger->error(std::string("Unable to load '") + fontFile + - std::string("': ") + e.getMessage()); + Log::critical(std::string("Unable to load '") + fontFile + + "': " + e.getMessage()); } loadCustomCursors(); @@ -288,32 +288,20 @@ void Gui::loadCustomCursors() SDL_Surface *mouseSurface = loadSurface(cursorPath); if (!mouseSurface) { - logger->log("Warning: Unable to load mouse cursor file (%s): %s", - cursorPath.c_str(), SDL_GetError()); + Log::warn("Unable to load mouse cursor file (%s): %s", + cursorPath.c_str(), SDL_GetError()); return; } SDL_SetSurfaceBlendMode(mouseSurface, SDL_BLENDMODE_NONE); -#if SDL_BYTEORDER == SDL_BIG_ENDIAN - const Uint32 rmask = 0xff000000; - const Uint32 gmask = 0x00ff0000; - const Uint32 bmask = 0x0000ff00; - const Uint32 amask = 0x000000ff; -#else - const Uint32 rmask = 0x000000ff; - const Uint32 gmask = 0x0000ff00; - const Uint32 bmask = 0x00ff0000; - const Uint32 amask = 0xff000000; -#endif - constexpr int cursorSize = 40; const int targetCursorSize = cursorSize * mCustomCursorScale; const int columns = mouseSurface->w / cursorSize; - SDL_Surface *cursorSurface = SDL_CreateRGBSurface( + SDL_Surface *cursorSurface = SDL_CreateRGBSurfaceWithFormat( 0, targetCursorSize, targetCursorSize, 32, - rmask, gmask, bmask, amask); + SDL_PIXELFORMAT_RGBA32); for (int i = 0; i < static_cast<int>(Cursor::Count); ++i) { @@ -329,7 +317,7 @@ void Gui::loadCustomCursors() 17 * mCustomCursorScale); if (!cursor) { - logger->log("Warning: Unable to create cursor: %s", SDL_GetError()); + Log::warn("Unable to create cursor: %s", SDL_GetError()); } mCustomMouseCursors.push_back(cursor); diff --git a/src/gui/helpwindow.cpp b/src/gui/helpwindow.cpp index e0e21610..7c7c5d4c 100644 --- a/src/gui/helpwindow.cpp +++ b/src/gui/helpwindow.cpp @@ -45,7 +45,7 @@ HelpWindow::HelpWindow(): setResizable(true); setupWindow->registerWindowForReset(this); - setDefaultSize(500, 400, ImageRect::CENTER); + setDefaultSize(500, 400, WindowAlignment::Center); mBrowserBox = new BrowserBox; mScrollArea = new ScrollArea(mBrowserBox); @@ -98,7 +98,7 @@ void HelpWindow::loadFile(const std::string &file) char *fileContents = (char *) FS::loadFile(fileName, contentsLength); if (!fileContents) { - logger->log("Couldn't load text file: %s", fileName.c_str()); + Log::info("Couldn't load text file: %s", fileName.c_str()); return; } diff --git a/src/gui/inventorywindow.cpp b/src/gui/inventorywindow.cpp index ab2e9c86..0125700c 100644 --- a/src/gui/inventorywindow.cpp +++ b/src/gui/inventorywindow.cpp @@ -65,7 +65,7 @@ InventoryWindow::InventoryWindow(Inventory *inventory): setCloseButton(true); setSaveVisible(true); - setDefaultSize(387, 307, ImageRect::CENTER); + setDefaultSize(387, 307, WindowAlignment::Center); setMinWidth(316); setMinHeight(179); addKeyListener(this); diff --git a/src/gui/npcdialog.cpp b/src/gui/npcdialog.cpp index 16e7db94..033d01cc 100644 --- a/src/gui/npcdialog.cpp +++ b/src/gui/npcdialog.cpp @@ -82,7 +82,7 @@ NpcDialog::NpcDialog(int npcId) setMinWidth(200); setMinHeight(150); - setDefaultSize(260, 200, ImageRect::CENTER); + setDefaultSize(260, 200, WindowAlignment::Center); // Setup output text box mTextBox = new BrowserBox(BrowserBox::AUTO_WRAP); diff --git a/src/gui/popupmenu.cpp b/src/gui/popupmenu.cpp index 4bafc074..16b16af9 100644 --- a/src/gui/popupmenu.cpp +++ b/src/gui/popupmenu.cpp @@ -318,7 +318,7 @@ void PopupMenu::handleLink(const std::string &link) // Unknown actions else if (link != "cancel") { - logger->log("PopupMenu: Warning, unknown action '%s'", link.c_str()); + Log::info("PopupMenu: Warning, unknown action '%s'", link.c_str()); } setVisible(false); diff --git a/src/gui/questswindow.cpp b/src/gui/questswindow.cpp new file mode 100644 index 00000000..6769815e --- /dev/null +++ b/src/gui/questswindow.cpp @@ -0,0 +1,290 @@ +/* + * The Mana Client + * Copyright (C) 2025 The Mana Developers + * + * This file is part of The Mana Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "questswindow.h" + +#include "configuration.h" + +#include "gui/setup.h" + +#include "gui/widgets/browserbox.h" +#include "gui/widgets/checkbox.h" +#include "gui/widgets/itemlinkhandler.h" +#include "gui/widgets/layout.h" +#include "gui/widgets/listbox.h" +#include "gui/widgets/scrollarea.h" + +#include "net/net.h" +#include "net/playerhandler.h" + +#include "resources/questdb.h" + +#include "utils/gettext.h" + +#include <guichan/font.hpp> + +#include <algorithm> + +class QuestsModel final : public gcn::ListModel +{ +public: + int getNumberOfElements() override + { return mQuests.size(); } + + std::string getElementAt(int i) override + { return mQuests[i].name(); } + + const std::vector<QuestEntry> &getQuests() const + { return mQuests; } + + void setQuests(const std::vector<QuestEntry> &quests) + { mQuests = quests; } + +private: + std::vector<QuestEntry> mQuests; +}; + + +class QuestsListBox final : public ListBox +{ +public: + QuestsListBox(QuestsModel *model) + : ListBox(model) + {} + + unsigned getRowHeight() const override; + + void draw(gcn::Graphics *graphics) override; +}; + +unsigned QuestsListBox::getRowHeight() const +{ + auto rowHeight = ListBox::getRowHeight(); + + if (auto icon = gui->getTheme()->getIcon("complete")) + rowHeight = std::max<unsigned>(rowHeight, icon->getHeight() + 2); + + return rowHeight; +} + +void QuestsListBox::draw(gcn::Graphics *gcnGraphics) +{ + if (!mListModel) + return; + + auto *graphics = static_cast<Graphics *>(gcnGraphics); + auto *model = static_cast<QuestsModel *>(getListModel()); + + const int rowHeight = getRowHeight(); + + auto theme = gui->getTheme(); + auto completeIcon = theme->getIcon("complete"); + auto incompleteIcon = theme->getIcon("incomplete"); + + // Draw filled rectangle around the selected list element + if (mSelected >= 0) + { + auto highlightColor = Theme::getThemeColor(Theme::HIGHLIGHT); + highlightColor.a = gui->getTheme()->getGuiAlpha(); + graphics->setColor(highlightColor); + graphics->fillRectangle(gcn::Rectangle(0, rowHeight * mSelected, + getWidth(), rowHeight)); + } + + // Draw the list elements + graphics->setFont(getFont()); + graphics->setColor(Theme::getThemeColor(Theme::TEXT)); + + const int fontHeight = getFont()->getHeight(); + + for (int i = 0, y = 0; i < model->getNumberOfElements(); + ++i, y += rowHeight) + { + if (mSelected == i) + graphics->setColor(Theme::getThemeColor(Theme::HIGHLIGHT_TEXT)); + else + graphics->setColor(Theme::getThemeColor(Theme::TEXT)); + + auto &quest = model->getQuests()[i]; + int x = 1; + + if (const Image *icon = quest.completed ? completeIcon : incompleteIcon) + { + graphics->drawImage(icon, x, y + (rowHeight - icon->getHeight()) / 2); + x += icon->getWidth() + 4; + } + + graphics->drawText(quest.name(), x, y + (rowHeight - fontHeight) / 2); + } +} + + +QuestsWindow::QuestsWindow() + : Window(_("Quests")) + , mQuestsModel(std::make_unique<QuestsModel>()) + , mQuestsListBox(new QuestsListBox(mQuestsModel.get())) + , mHideCompletedCheckBox(new CheckBox(_("Hide completed"), config.hideCompletedQuests)) + , mQuestDetails(new BrowserBox(BrowserBox::AUTO_WRAP)) + , mLinkHandler(std::make_unique<ItemLinkHandler>()) +{ + setWindowName("Quests"); + setupWindow->registerWindowForReset(this); + setResizable(true); + setCloseButton(true); + setSaveVisible(true); + + setDefaultSize(387, 307, WindowAlignment::Center); + setMinWidth(316); + setMinHeight(179); + + mQuestsListBox->addSelectionListener(this); + mHideCompletedCheckBox->setActionEventId("hideCompleted"); + mHideCompletedCheckBox->addActionListener(this); + + auto questListScrollArea = new ScrollArea(mQuestsListBox); + questListScrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); + + mQuestDetails->setLinkHandler(mLinkHandler.get()); + mQuestDetailsScrollArea = new ScrollArea(mQuestDetails); + mQuestDetailsScrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); + + auto place = getPlacer(0, 0); + place(0, 0, questListScrollArea, 2, 2).setPadding(2); + place(2, 0, mQuestDetailsScrollArea, 3, 2).setPadding(2); + place = getPlacer(0, 1); + place(0, 0, mHideCompletedCheckBox); + + getLayout().setRowHeight(1, 0); // Don't scale up the bottom row + + listen(Event::QuestsChannel); + + refreshQuestList(); + loadWindowState(); +} + +QuestsWindow::~QuestsWindow() = default; + +void QuestsWindow::action(const gcn::ActionEvent &event) +{ + if (event.getId() == "hideCompleted") + { + config.hideCompletedQuests = mHideCompletedCheckBox->isSelected(); + refreshQuestList(); + } +} + +void QuestsWindow::valueChanged(const gcn::SelectionEvent &event) +{ + if (mSelectedQuestIndex != mQuestsListBox->getSelected()) + updateQuestDetails(); +} + +void QuestsWindow::event(Event::Channel channel, const Event &event) +{ + if (channel == Event::QuestsChannel) + { + if (event.getType() == Event::QuestVarsChanged) + refreshQuestList(); + } +} + +void QuestsWindow::refreshQuestList() +{ + // Store the currently selected quest state and varId to preserve selection + const QuestState *selectedQuestState = nullptr; + int selectedVarId = -1; + if (mSelectedQuestIndex >= 0 && mSelectedQuestIndex < mQuestsModel->getNumberOfElements()) + { + const auto &selectedQuest = mQuestsModel->getQuests().at(mSelectedQuestIndex); + selectedQuestState = selectedQuest.state; + selectedVarId = selectedQuest.varId; + } + + auto &questVars = Net::getPlayerHandler()->getQuestVars(); + auto newQuests = QuestDB::getQuestsEntries(questVars, config.hideCompletedQuests); + + // Put completed quests at the top + std::stable_sort(newQuests.begin(), newQuests.end(), [](const QuestEntry &a, const QuestEntry &b) { + return a.completed > b.completed; + }); + + mQuestsModel->setQuests(newQuests); + + if (!selectedQuestState) + return; + + // Try to find and reselect the same quest, preferring exact state match + int newSelectedIndex = -1; + + for (int i = 0; i < static_cast<int>(newQuests.size()); ++i) + { + if (newQuests[i].state == selectedQuestState) + { + newSelectedIndex = i; + break; + } + else if (newSelectedIndex == -1 && newQuests[i].varId == selectedVarId) + { + newSelectedIndex = i; + // Don't break here - continue looking for exact state match + } + } + + if (mSelectedQuestIndex != newSelectedIndex) + mQuestsListBox->setSelected(newSelectedIndex); + else + updateQuestDetails(); +} + +void QuestsWindow::updateQuestDetails() +{ + mQuestDetails->clearRows(); + + mSelectedQuestIndex = mQuestsListBox->getSelected(); + if (mSelectedQuestIndex < 0 || mSelectedQuestIndex >= mQuestsModel->getNumberOfElements()) + return; + + const QuestEntry &quest = mQuestsModel->getQuests().at(mSelectedQuestIndex); + for (const auto &row : quest.rows()) + { + switch (row.type) + { + case QuestRowType::Text: + mQuestDetails->addRow(row.text); + break; + case QuestRowType::Name: + mQuestDetails->addRow("[" + row.text + "]"); + break; + case QuestRowType::Reward: + mQuestDetails->addRow(strprintf(_("Reward: %s"), row.text.c_str())); + break; + case QuestRowType::Giver: + mQuestDetails->addRow(strprintf(_("Quest Giver: %s"), row.text.c_str())); + break; + case QuestRowType::Coordinates: + mQuestDetails->addRow(strprintf(_("Coordinates: %s (%d, %d)"), + row.text.c_str(), row.x, row.y)); + break; + case QuestRowType::NPC: + mQuestDetails->addRow(strprintf(_("NPC: %s"), row.text.c_str())); + break; + } + } +} diff --git a/src/gui/questswindow.h b/src/gui/questswindow.h new file mode 100644 index 00000000..a479f826 --- /dev/null +++ b/src/gui/questswindow.h @@ -0,0 +1,71 @@ +/* + * The Mana Client + * Copyright (C) 2025 The Mana Developers + * + * This file is part of The Mana Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once + +#include "eventlistener.h" + +#include "gui/widgets/window.h" + +#include <guichan/actionlistener.hpp> +#include <guichan/keylistener.hpp> +#include <guichan/selectionlistener.hpp> + +class BrowserBox; +class CheckBox; +class LinkHandler; +class QuestsListBox; +class QuestsModel; +class ScrollArea; + +/** + * Quests window. + * + * \ingroup Interface + */ +class QuestsWindow final : public Window, + public gcn::ActionListener, + public gcn::SelectionListener, + public EventListener +{ +public: + QuestsWindow(); + ~QuestsWindow(); + + void action(const gcn::ActionEvent &event) override; + + void valueChanged(const gcn::SelectionEvent &event) override; + + void event(Event::Channel channel, const Event &event) override; + +private: + void refreshQuestList(); + void updateQuestDetails(); + + int mSelectedQuestIndex = -1; + std::unique_ptr<QuestsModel> mQuestsModel; + QuestsListBox *mQuestsListBox; + CheckBox *mHideCompletedCheckBox; + BrowserBox *mQuestDetails; + ScrollArea *mQuestDetailsScrollArea; + std::unique_ptr<LinkHandler> mLinkHandler; +}; + +extern QuestsWindow *questsWindow; diff --git a/src/gui/recorder.cpp b/src/gui/recorder.cpp index 894e3631..96e458ff 100644 --- a/src/gui/recorder.cpp +++ b/src/gui/recorder.cpp @@ -47,7 +47,7 @@ Recorder::Recorder(ChatWindow *chat, // 123 is the default chat window height. If you change this in Chat, please // change it here as well setDefaultSize(button->getWidth() + offsetX, button->getHeight() + - offsetY, ImageRect::LOWER_LEFT, 0, 123); + offsetY, WindowAlignment::BottomLeft, 0, 123); place(0, 0, button); diff --git a/src/gui/register.cpp b/src/gui/register.cpp index 62114c10..d7924021 100644 --- a/src/gui/register.cpp +++ b/src/gui/register.cpp @@ -147,7 +147,7 @@ void RegisterDialog::action(const gcn::ActionEvent &event) else if (event.getId() == "register" && canSubmit()) { const std::string user = mUserField->getText(); - logger->log("RegisterDialog::register Username is %s", user.c_str()); + Log::info("RegisterDialog::register Username is %s", user.c_str()); std::string errorMessage; int error = 0; diff --git a/src/gui/selldialog.cpp b/src/gui/selldialog.cpp index 4aeacd6f..4fa12e53 100644 --- a/src/gui/selldialog.cpp +++ b/src/gui/selldialog.cpp @@ -56,7 +56,7 @@ SellDialog::SellDialog(int npcId): setCloseButton(true); setMinWidth(260); setMinHeight(230); - setDefaultSize(260, 230, ImageRect::CENTER); + setDefaultSize(260, 230, WindowAlignment::Center); // Create a ShopItems instance, that is aware of duplicate entries. mShopItems = new ShopItems(true); diff --git a/src/gui/serverdialog.cpp b/src/gui/serverdialog.cpp index f5418625..e41c0bbe 100644 --- a/src/gui/serverdialog.cpp +++ b/src/gui/serverdialog.cpp @@ -115,7 +115,10 @@ public: { const ServerInfo &info = model->getServer(i); - graphics->setColor(Theme::getThemeColor(Theme::TEXT)); + if (mSelected == i) + graphics->setColor(Theme::getThemeColor(Theme::HIGHLIGHT_TEXT)); + else + graphics->setColor(Theme::getThemeColor(Theme::TEXT)); if (!info.name.empty()) { @@ -201,7 +204,7 @@ ServerDialog::ServerDialog(ServerInfo *serverInfo, const std::string &dir): setMinWidth(getWidth()); setMinHeight(getHeight()); - setDefaultSize(getWidth(), getHeight(), ImageRect::CENTER); + setDefaultSize(getWidth(), getHeight(), WindowAlignment::Center); setResizable(true); addKeyListener(this); @@ -361,7 +364,7 @@ void ServerDialog::logic() case DownloadStatus::Canceled: case DownloadStatus::Error: mDownloadDone = true; - logger->log("Error retrieving server list: %s", mDownload->getError()); + Log::info("Error retrieving server list: %s", mDownload->getError()); mDownloadText->setCaption(_("Error retrieving server list!")); break; @@ -406,15 +409,14 @@ void ServerDialog::loadServers() if (!rootNode || rootNode.name() != "serverlist") { - logger->log("Error loading server list!"); + Log::info("Error loading server list!"); return; } int version = rootNode.getProperty("version", 0); if (version != 1) { - logger->log("Error: unsupported online server list version: %d", - version); + Log::error("Unsupported online server list version: %d", version); return; } @@ -440,8 +442,8 @@ void ServerDialog::loadServer(XML::Node serverNode) #endif ) { - logger->log("Ignoring server entry with unknown type: %s", - type.c_str()); + Log::info("Ignoring server entry with unknown type: %s", + type.c_str()); return; } diff --git a/src/gui/setup_audio.cpp b/src/gui/setup_audio.cpp index 43b132d8..0031f9bc 100644 --- a/src/gui/setup_audio.cpp +++ b/src/gui/setup_audio.cpp @@ -108,7 +108,7 @@ void Setup_Audio::apply() catch (const char *err) { new OkDialog(_("Sound Engine"), err); - logger->log("Warning: %s", err); + Log::warn("%s", err); } } else diff --git a/src/gui/shortcutwindow.cpp b/src/gui/shortcutwindow.cpp index 2cffbb81..c33fcf01 100644 --- a/src/gui/shortcutwindow.cpp +++ b/src/gui/shortcutwindow.cpp @@ -49,10 +49,13 @@ ShortcutWindow::ShortcutWindow(const std::string &title, const int border = (getPadding() + content->getFrameSize()) * 2; setMinWidth(content->getBoxWidth() + border); setMinHeight(content->getBoxHeight() + border + GRAB_MARGIN); - setMaxWidth(content->getBoxWidth() * content->getMaxItems() + border); - setMaxHeight(content->getBoxHeight() * content->getMaxItems() + border + GRAB_MARGIN); - setDefaultSize(getMinWidth(), getMaxHeight(), ImageRect::LOWER_RIGHT); + const int maxContentWidth = content->getBoxWidth() * content->getMaxItems(); + const int maxContentHeight = content->getBoxHeight() * content->getMaxItems(); + setMaxWidth(std::max(getMinWidth(), maxContentWidth + border)); + setMaxHeight(std::max(getMinHeight(), maxContentHeight + border + GRAB_MARGIN)); + + setDefaultSize(getMinWidth(), getMaxHeight(), WindowAlignment::BottomRight); place(0, 0, scrollArea, 5, 5).setPadding(0); diff --git a/src/gui/skilldialog.cpp b/src/gui/skilldialog.cpp index 40421daf..49552421 100644 --- a/src/gui/skilldialog.cpp +++ b/src/gui/skilldialog.cpp @@ -147,11 +147,15 @@ public: } // Draw the list elements - graphics->setColor(Theme::getThemeColor(Theme::TEXT)); for (int i = 0, y = 1; i < model->getNumberOfElements(); ++i, y += getRowHeight()) { + if (mSelected == i) + graphics->setColor(Theme::getThemeColor(Theme::HIGHLIGHT_TEXT)); + else + graphics->setColor(Theme::getThemeColor(Theme::TEXT)); + if (SkillInfo *e = model->getSkillAt(i)) e->draw(graphics, y, getWidth()); } @@ -290,7 +294,7 @@ void SkillDialog::loadSkills() if (!root || root.name() != "skills") { - logger->log("Error loading skills file: %s", SKILLS_FILE); + Log::info("Error loading skills file: %s", SKILLS_FILE); if (Net::getNetworkType() == ServerType::TmwAthena) { diff --git a/src/gui/tradewindow.cpp b/src/gui/tradewindow.cpp index e24845b7..6610bd43 100644 --- a/src/gui/tradewindow.cpp +++ b/src/gui/tradewindow.cpp @@ -60,7 +60,7 @@ TradeWindow::TradeWindow(): setWindowName("Trade"); setResizable(true); setCloseButton(true); - setDefaultSize(386, 180, ImageRect::CENTER); + setDefaultSize(386, 180, WindowAlignment::Center); setMinWidth(386); setMinHeight(180); setupWindow->registerWindowForReset(this); diff --git a/src/gui/truetypefont.cpp b/src/gui/truetypefont.cpp index 444641b5..c85d08c0 100644 --- a/src/gui/truetypefont.cpp +++ b/src/gui/truetypefont.cpp @@ -53,6 +53,7 @@ bool operator==(SDL_Color lhs, SDL_Color rhs) lhs.a == rhs.a); } + class TextChunk { public: @@ -60,24 +61,49 @@ public: : text(text) {} - void generate(TTF_Font *font) + void render(Graphics *graphics, + int x, int y, + TTF_Font *font, + std::unique_ptr<Image> &img, + float scale); + + const std::string text; + std::unique_ptr<Image> regular; + std::unique_ptr<Image> outlined; +}; + +void TextChunk::render(Graphics *graphics, + int x, int y, + TTF_Font *font, + std::unique_ptr<Image> &img, + float scale) +{ + if (!img) { // Always render in white, we'll use color modulation when rendering + constexpr SDL_Color white = { 255, 255, 255, 255 }; SDL_Surface *surface = TTF_RenderUTF8_Blended(font, getSafeUtf8String(text), - SDL_Color { 255, 255, 255, 255 }); + white); - if (!surface) - return; + if (surface) + { + img.reset(Image::load(surface)); + SDL_FreeSurface(surface); + } + } - img.reset(Image::load(surface)); + if (img) + { + graphics->drawRescaledImageF(img.get(), 0, 0, x, y, + img->getWidth(), + img->getHeight(), + img->getWidth() / scale, + img->getHeight() / scale, true); - SDL_FreeSurface(surface); } +} - std::unique_ptr<Image> img; - const std::string text; -}; std::list<TrueTypeFont*> TrueTypeFont::mFonts; float TrueTypeFont::mScale = 1.0f; @@ -85,6 +111,7 @@ float TrueTypeFont::mScale = 1.0f; TrueTypeFont::TrueTypeFont(const std::string &filename, int size, int style) : mFilename(filename) , mPointSize(size) + , mStyle(style) { if (TTF_Init() == -1) { @@ -93,14 +120,18 @@ TrueTypeFont::TrueTypeFont(const std::string &filename, int size, int style) } mFont = TTF_OpenFont(filename.c_str(), size * mScale); + mFontOutline = TTF_OpenFont(filename.c_str(), size * mScale); - if (!mFont) + if (!mFont || !mFontOutline) { throw GCN_EXCEPTION("SDLTrueTypeFont::SDLTrueTypeFont: " + std::string(TTF_GetError())); } TTF_SetFontStyle(mFont, style); + TTF_SetFontStyle(mFontOutline, style); + + TTF_SetFontOutline(mFontOutline, static_cast<int>(mScale)); mFonts.push_back(this); } @@ -112,6 +143,9 @@ TrueTypeFont::~TrueTypeFont() if (mFont) TTF_CloseFont(mFont); + if (mFontOutline) + TTF_CloseFont(mFontOutline); + TTF_Quit(); } @@ -123,37 +157,41 @@ void TrueTypeFont::drawString(gcn::Graphics *graphics, return; auto *g = static_cast<Graphics *>(graphics); + TextChunk &chunk = getChunk(text); - bool found = false; + chunk.render(g, x, y, mFont, chunk.regular, mScale); +} - for (auto i = mCache.begin(); i != mCache.end(); ++i) - { - auto &chunk = *i; - if (chunk.text == text) - { - // Raise priority: move it to front - mCache.splice(mCache.begin(), mCache, i); - found = true; - break; - } - } +void TrueTypeFont::drawString(Graphics *graphics, + const std::string &text, + int x, int y, + const std::optional<gcn::Color> &outlineColor, + const std::optional<gcn::Color> &shadowColor) +{ + if (text.empty()) + return; + + auto *g = static_cast<Graphics *>(graphics); + auto color = graphics->getColor(); + TextChunk &chunk = getChunk(text); - if (!found) + if (shadowColor) { - if (mCache.size() >= CACHE_SIZE) - mCache.pop_back(); - mCache.emplace_front(text); - mCache.front().generate(mFont); + g->setColor(*shadowColor); + if (outlineColor) + chunk.render(g, x, y, mFontOutline, chunk.outlined, mScale); + else + chunk.render(g, x + 1, y + 1, mFont, chunk.regular, mScale); } - if (auto img = mCache.front().img.get()) + if (outlineColor) { - g->drawRescaledImageF(img, 0, 0, x, y, - img->getWidth(), - img->getHeight(), - img->getWidth() / mScale, - img->getHeight() / mScale, true); + g->setColor(*outlineColor); + chunk.render(g, x - 1, y - 1, mFontOutline, chunk.outlined, mScale); } + + g->setColor(color); + chunk.render(g, x, y, mFont, chunk.regular, mScale); } void TrueTypeFont::updateFontScale(float scale) @@ -167,9 +205,16 @@ void TrueTypeFont::updateFontScale(float scale) { #if SDL_TTF_VERSION_ATLEAST(2, 0, 18) TTF_SetFontSize(font->mFont, font->mPointSize * mScale); + TTF_SetFontSize(font->mFontOutline, font->mPointSize * mScale); + TTF_SetFontOutline(font->mFontOutline, mScale); #else TTF_CloseFont(font->mFont); + TTF_CloseFont(font->mFontOutline); font->mFont = TTF_OpenFont(font->mFilename.c_str(), font->mPointSize * mScale); + font->mFontOutline = TTF_OpenFont(font->mFilename.c_str(), font->mPointSize * mScale); + TTF_SetFontStyle(font->mFont, font->mStyle); + TTF_SetFontStyle(font->mFontOutline, font->mStyle); + TTF_SetFontOutline(font->mFontOutline, mScale); #endif font->mCache.clear(); @@ -178,19 +223,11 @@ void TrueTypeFont::updateFontScale(float scale) int TrueTypeFont::getWidth(const std::string &text) const { - for (auto i = mCache.begin(); i != mCache.end(); i++) - { - if (i->text == text) - { - // Raise priority: move it to front - // Assumption is that TTF::draw will be called next - mCache.splice(mCache.begin(), mCache, i); - if (i->img) - return std::ceil(i->img->getWidth() / mScale); - return 0; - } - } + TextChunk &chunk = getChunk(text); + if (auto img = chunk.regular.get()) + return std::ceil(img->getWidth() / mScale); + // If the image wasn't created yet, just calculate the width of the text int w, h; TTF_SizeUTF8(mFont, getSafeUtf8String(text), &w, &h); return std::ceil(w / mScale); @@ -205,3 +242,21 @@ int TrueTypeFont::getLineHeight() const { return std::ceil(TTF_FontLineSkip(mFont) / mScale); } + +TextChunk &TrueTypeFont::getChunk(const std::string &text) const +{ + for (auto i = mCache.begin(); i != mCache.end(); i++) + { + if (i->text == text) + { + // Raise priority: move it to front + mCache.splice(mCache.begin(), mCache, i); + return *i; + } + } + + if (mCache.size() >= CACHE_SIZE) + mCache.pop_back(); + + return mCache.emplace_front(text); +} diff --git a/src/gui/truetypefont.h b/src/gui/truetypefont.h index a479537d..f88938ff 100644 --- a/src/gui/truetypefont.h +++ b/src/gui/truetypefont.h @@ -22,13 +22,16 @@ #pragma once +#include <guichan/color.hpp> #include <guichan/font.hpp> #include <SDL_ttf.h> #include <list> +#include <optional> #include <string> +class Graphics; class TextChunk; /** @@ -46,11 +49,13 @@ class TrueTypeFont : public gcn::Font * @param size Font size. */ TrueTypeFont(const std::string &filename, int size, int style = 0); - ~TrueTypeFont() override; - int getWidth(const std::string &text) const override; + const std::string &filename() const { return mFilename; } + int pointSize() const { return mPointSize; } + int style() const { return mStyle; } + int getWidth(const std::string &text) const override; int getHeight() const override; /** @@ -67,13 +72,27 @@ class TrueTypeFont : public gcn::Font const std::string &text, int x, int y) override; + /** + * Extended version of drawString that allows for rendering text with + * outline and/or shadow. + */ + void drawString(Graphics *graphics, + const std::string &text, + int x, int y, + const std::optional<gcn::Color> &outlineColor, + const std::optional<gcn::Color> &shadowColor); + static void updateFontScale(float scale); private: + TextChunk &getChunk(const std::string &text) const; + const std::string mFilename; - TTF_Font *mFont; + TTF_Font *mFont = nullptr; + TTF_Font *mFontOutline = nullptr; const int mPointSize; + const int mStyle; // Word surfaces cache mutable std::list<TextChunk> mCache; diff --git a/src/gui/unregisterdialog.cpp b/src/gui/unregisterdialog.cpp index 94f6ef62..2abbebf7 100644 --- a/src/gui/unregisterdialog.cpp +++ b/src/gui/unregisterdialog.cpp @@ -98,8 +98,8 @@ void UnRegisterDialog::action(const gcn::ActionEvent &event) else if (event.getId() == "unregister") { const std::string &password = mPasswordField->getText(); - logger->log("UnregisterDialog::unregistered, Username is %s", - mLoginData->username.c_str()); + Log::info("UnregisterDialog::unregistered, Username is %s", + mLoginData->username.c_str()); std::stringstream errorMessage; bool error = false; diff --git a/src/gui/updaterwindow.cpp b/src/gui/updaterwindow.cpp index 5cfb45cd..c16c3e04 100644 --- a/src/gui/updaterwindow.cpp +++ b/src/gui/updaterwindow.cpp @@ -60,7 +60,7 @@ std::vector<UpdateFile> loadXMLFile(const std::string &fileName) if (!rootNode || rootNode.name() != "updates") { - logger->log("Error loading update file: %s", fileName.c_str()); + Log::info("Error loading update file: %s", fileName.c_str()); return files; } @@ -110,7 +110,7 @@ std::vector<UpdateFile> loadTxtFile(const std::string &fileName) } else { - logger->log("Error loading update file: %s", fileName.c_str()); + Log::info("Error loading update file: %s", fileName.c_str()); } fileHandler.close(); @@ -128,7 +128,7 @@ UpdaterWindow::UpdaterWindow(const std::string &updateHost, { setWindowName("UpdaterWindow"); setResizable(true); - setDefaultSize(450, 400, ImageRect::CENTER); + setDefaultSize(450, 400, WindowAlignment::Center); setMinWidth(320); setMinHeight(240); @@ -258,9 +258,9 @@ void UpdaterWindow::loadUpdates() mUpdateFiles = loadXMLFile(mUpdatesDir + "/" + xmlUpdateFile); if (mUpdateFiles.empty()) { - logger->log("Warning this server does not have a" - " %s file falling back to %s", xmlUpdateFile, - txtUpdateFile); + Log::warn("This server does not have a" + " %s file falling back to %s", xmlUpdateFile, + txtUpdateFile); mUpdateFiles = loadTxtFile(mUpdatesDir + "/" + txtUpdateFile); } } @@ -336,9 +336,9 @@ void UpdaterWindow::downloadCompleted() mUpdateFiles = loadXMLFile(mUpdatesDir + "/" + xmlUpdateFile); if (mUpdateFiles.empty()) { - logger->log("Warning this server does not have a %s" - " file falling back to %s", - xmlUpdateFile, txtUpdateFile); + Log::warn("This server does not have a %s" + " file falling back to %s", + xmlUpdateFile, txtUpdateFile); // If the resources.xml file fails, fall back onto a older version mDialogState = DialogState::DownloadList; @@ -383,7 +383,7 @@ void UpdaterWindow::downloadCompleted() else { fclose(file); - logger->log("%s already here", thisFile.name.c_str()); + Log::info("%s already here", thisFile.name.c_str()); } mUpdateIndex++; } diff --git a/src/gui/viewport.cpp b/src/gui/viewport.cpp index 9e529063..3d90846e 100644 --- a/src/gui/viewport.cpp +++ b/src/gui/viewport.cpp @@ -278,7 +278,7 @@ void Viewport::_followMouse() mMouseY = static_cast<int>(logicalY); // If the left button is dragged - if (mPlayerFollowMouse && button & SDL_BUTTON(1)) + if (mPlayerFollowMouse && button & SDL_BUTTON_LMASK) { // We create a mouse event and send it to mouseDragged. const Uint8 *keys = SDL_GetKeyboardState(nullptr); diff --git a/src/gui/widgets/avatarlistbox.cpp b/src/gui/widgets/avatarlistbox.cpp index 4a806d04..a5109267 100644 --- a/src/gui/widgets/avatarlistbox.cpp +++ b/src/gui/widgets/avatarlistbox.cpp @@ -76,11 +76,15 @@ void AvatarListBox::draw(gcn::Graphics *gcnGraphics) auto offlineIcon = theme->getIcon("offline"); // Draw the list elements - graphics->setColor(Theme::getThemeColor(Theme::TEXT)); for (int i = 0, y = 0; i < model->getNumberOfElements(); ++i, y += rowHeight) { + if (mSelected == i) + graphics->setColor(Theme::getThemeColor(Theme::HIGHLIGHT_TEXT)); + else + graphics->setColor(Theme::getThemeColor(Theme::TEXT)); + Avatar *a = model->getAvatarAt(i); int x = 1; diff --git a/src/gui/widgets/browserbox.cpp b/src/gui/widgets/browserbox.cpp index 4fe85ae5..bf337a0f 100644 --- a/src/gui/widgets/browserbox.cpp +++ b/src/gui/widgets/browserbox.cpp @@ -23,7 +23,6 @@ #include "gui/widgets/browserbox.h" #include "keyboardconfig.h" -#include "textrenderer.h" #include "gui/gui.h" #include "gui/truetypefont.h" @@ -228,7 +227,7 @@ void BrowserBox::addRow(std::string_view row) void BrowserBox::clearRows() { mTextRows.clear(); - setSize(0, 0); + setSize(mMode == AUTO_SIZE ? 0 : getWidth(), 0); mHoveredLink.reset(); maybeRelayoutText(); } @@ -292,6 +291,8 @@ void BrowserBox::draw(gcn::Graphics *graphics) } } + auto g = static_cast<Graphics*>(graphics); + for (const auto &row : mTextRows) { for (const auto &part : row.parts) @@ -301,16 +302,15 @@ void BrowserBox::draw(gcn::Graphics *graphics) if (part.y > yEnd) return; - TextRenderer::renderText(graphics, - part.text, - part.x, - part.y, - Graphics::LEFT, - part.color, - part.font, - part.outlineColor.has_value() || mOutline, - mShadows, - part.outlineColor); + g->drawText(part.text, + part.x, + part.y, + Graphics::LEFT, + part.color, + part.font, + part.outlineColor.has_value() || mOutline, + mShadows, + part.outlineColor); } } } diff --git a/src/gui/widgets/button.cpp b/src/gui/widgets/button.cpp index 31c3a677..604f5dc8 100644 --- a/src/gui/widgets/button.cpp +++ b/src/gui/widgets/button.cpp @@ -28,7 +28,6 @@ #include "resources/image.h" #include "resources/theme.h" -#include "textrenderer.h" #include <guichan/exception.hpp> #include <guichan/font.hpp> @@ -132,8 +131,9 @@ void Button::draw(gcn::Graphics *graphics) if (isPressed()) widgetState.flags |= STATE_SELECTED; + auto g = static_cast<Graphics *>(graphics); auto &skin = gui->getTheme()->getSkin(SkinType::Button); - skin.draw(static_cast<Graphics *>(graphics), widgetState); + skin.draw(g, widgetState); auto skinState = skin.getState(widgetState.flags); auto font = (skinState && skinState->textFormat.bold) ? boldFont : getFont(); @@ -196,18 +196,16 @@ void Button::draw(gcn::Graphics *graphics) } if (btnIconWidth) - static_cast<Graphics *>(graphics)->drawImage(icon, btnIconX, btnIconY); + g->drawImage(icon, btnIconX, btnIconY); if (auto skinState = skin.getState(widgetState.flags)) { - auto &textFormat = skinState->textFormat; - TextRenderer::renderText(static_cast<Graphics *>(graphics), - getCaption(), - textX, - textY, - getAlignment(), - font, - textFormat); + g->drawText(getCaption(), + textX, + textY, + getAlignment(), + font, + skinState->textFormat); } } diff --git a/src/gui/widgets/chattab.h b/src/gui/widgets/chattab.h index dfc07638..5232392f 100644 --- a/src/gui/widgets/chattab.h +++ b/src/gui/widgets/chattab.h @@ -24,7 +24,6 @@ #include "gui/chatwindow.h" #include "gui/widgets/tab.h" -#include "gui/widgets/textfield.h" class BrowserBox; class Recorder; diff --git a/src/gui/widgets/checkbox.cpp b/src/gui/widgets/checkbox.cpp index e6079f2f..4bb0bb72 100644 --- a/src/gui/widgets/checkbox.cpp +++ b/src/gui/widgets/checkbox.cpp @@ -21,8 +21,6 @@ #include "gui/widgets/checkbox.h" -#include "textrenderer.h" - #include "gui/gui.h" #include "resources/theme.h" @@ -44,19 +42,19 @@ void CheckBox::draw(gcn::Graphics* graphics) if (isSelected()) widgetState.flags |= STATE_SELECTED; + auto g = static_cast<Graphics *>(graphics); auto &skin = gui->getTheme()->getSkin(SkinType::CheckBox); - skin.draw(static_cast<Graphics *>(graphics), widgetState); + skin.draw(g, widgetState); if (auto skinState = skin.getState(widgetState.flags)) { auto &textFormat = skinState->textFormat; - TextRenderer::renderText(static_cast<Graphics *>(graphics), - getCaption(), - skin.getMinWidth() + skin.padding + skin.spacing, - skin.padding, - Graphics::LEFT, - textFormat.bold ? boldFont : getFont(), - textFormat); + g->drawText(getCaption(), + skin.getMinWidth() + skin.padding + skin.spacing, + skin.padding, + Graphics::LEFT, + textFormat.bold ? boldFont : getFont(), + textFormat); } } diff --git a/src/gui/widgets/desktop.cpp b/src/gui/widgets/desktop.cpp index e424beec..b21c235a 100644 --- a/src/gui/widgets/desktop.cpp +++ b/src/gui/widgets/desktop.cpp @@ -113,6 +113,6 @@ void Desktop::setBestFittingWallpaper() } else { - logger->log("Couldn't load %s as wallpaper", wallpaperName.c_str()); + Log::info("Couldn't load %s as wallpaper", wallpaperName.c_str()); } } diff --git a/src/gui/widgets/itemcontainer.cpp b/src/gui/widgets/itemcontainer.cpp index 57e8a973..63388213 100644 --- a/src/gui/widgets/itemcontainer.cpp +++ b/src/gui/widgets/itemcontainer.cpp @@ -155,7 +155,7 @@ void ItemContainer::draw(gcn::Graphics *graphics) if (item->isEquipped()) g->setColor(theme->getColor(Theme::ITEM_EQUIPPED)); else - g->setColor(gcn::Color(0, 0, 0)); + g->setColor(theme->getColor(Theme::TEXT)); g->drawText(caption, itemX + slotSkin.width / 2, itemY + slotSkin.height - 14, gcn::Graphics::CENTER); @@ -354,9 +354,7 @@ void ItemContainer::mouseReleased(gcn::MouseEvent &event) // Show ItemTooltip void ItemContainer::mouseMoved(gcn::MouseEvent &event) { - Item *item = getItemAt(getSlotIndex(event.getX(), event.getY())); - - if (item) + if (Item *item = getItemAt(getSlotIndex(event.getX(), event.getY()))) { mItemPopup->setItem(item->getInfo()); mItemPopup->position(viewport->getMouseX(), viewport->getMouseY()); @@ -394,12 +392,17 @@ void ItemContainer::adjustHeight() int ItemContainer::getSlotIndex(int x, int y) const { + if (x >= getWidth() || y >= getHeight()) + return Inventory::NO_SLOT_INDEX; + auto &slotSkin = gui->getTheme()->getSkin(SkinType::ItemSlot); + const auto row = y / slotSkin.height; + const auto column = x / slotSkin.width; - if (x < getWidth() && y < getHeight()) - return (y / slotSkin.height) * mGridColumns + (x / slotSkin.width); + if (row < 0 || row >= mGridRows || column < 0 || column >= mGridColumns) + return Inventory::NO_SLOT_INDEX; - return Inventory::NO_SLOT_INDEX; + return (row * mGridColumns) + column; } void ItemContainer::keyAction() diff --git a/src/gui/widgets/itemlinkhandler.cpp b/src/gui/widgets/itemlinkhandler.cpp index f596fc82..d9d6f506 100644 --- a/src/gui/widgets/itemlinkhandler.cpp +++ b/src/gui/widgets/itemlinkhandler.cpp @@ -33,6 +33,7 @@ #include "gui/widgets/itemlinkhandler.h" +#include "client.h" #include "resources/iteminfo.h" #include "resources/itemdb.h" #include "utils/gettext.h" @@ -42,6 +43,7 @@ ItemLinkHandler::ItemLinkHandler(Window *parent) : mParent(parent) { mItemPopup = std::make_unique<ItemPopup>(); + mItemPopup->addDeathListener(this); } ItemLinkHandler::~ItemLinkHandler() = default; @@ -55,6 +57,24 @@ static bool isUrl(const std::string &link) void ItemLinkHandler::handleLink(const std::string &link) { +#if SDL_VERSION_ATLEAST(2, 0, 14) + // Handle screenshots by constructing full file path + if (startsWith(link, "screenshot:")) + { + std::string filename = link.substr(11); // Remove "screenshot:" prefix + + // Prevent directory traversal attacks or opening malicious files + if (filename.find("..") == std::string::npos && endsWith(filename, ".png")) + { + std::string fileUrl = "file://" + Client::getScreenshotDirectory() + "/" + filename; + if (SDL_OpenURL(fileUrl.c_str()) == -1) + new OkDialog(_("Open URL Failed"), SDL_GetError(), true, mParent); + } + + return; + } +#endif + if (isUrl(link)) { mLink = link; @@ -97,3 +117,10 @@ void ItemLinkHandler::action(const gcn::ActionEvent &actionEvent) #endif } } + +void ItemLinkHandler::death(const gcn::Event &event) +{ + // If somebody else killed the PopupUp, make sure we don't also try to delete it + if (event.getSource() == mItemPopup.get()) + mItemPopup.release(); +} diff --git a/src/gui/widgets/itemlinkhandler.h b/src/gui/widgets/itemlinkhandler.h index 58202d33..637482bd 100644 --- a/src/gui/widgets/itemlinkhandler.h +++ b/src/gui/widgets/itemlinkhandler.h @@ -24,13 +24,14 @@ #include "gui/widgets/linkhandler.h" #include <guichan/actionlistener.hpp> +#include <guichan/deathlistener.hpp> #include <memory> class ItemPopup; class Window; -class ItemLinkHandler : public LinkHandler, gcn::ActionListener +class ItemLinkHandler : public LinkHandler, gcn::ActionListener, public gcn::DeathListener { public: ItemLinkHandler(Window *parent = nullptr); @@ -42,6 +43,9 @@ class ItemLinkHandler : public LinkHandler, gcn::ActionListener // ActionListener interface void action(const gcn::ActionEvent &actionEvent) override; + // DeathListener interface + void death(const gcn::Event &event) override; + private: std::unique_ptr<ItemPopup> mItemPopup; diff --git a/src/gui/widgets/itemshortcutcontainer.cpp b/src/gui/widgets/itemshortcutcontainer.cpp index b7924a4b..b47fa29d 100644 --- a/src/gui/widgets/itemshortcutcontainer.cpp +++ b/src/gui/widgets/itemshortcutcontainer.cpp @@ -49,6 +49,7 @@ void ItemShortcutContainer::draw(gcn::Graphics *graphics) { auto *g = static_cast<Graphics*>(graphics); auto theme = gui->getTheme(); + auto &skin = theme->getSkin(SkinType::ShortcutBox); graphics->setFont(getFont()); @@ -57,21 +58,22 @@ void ItemShortcutContainer::draw(gcn::Graphics *graphics) WidgetState state; state.x = (i % mGridWidth) * mBoxWidth; state.y = (i / mGridWidth) * mBoxHeight; - theme->drawSkin(g, SkinType::ShortcutBox, state); + skin.draw(g, state); // Draw item keyboard shortcut. const char *key = SDL_GetKeyName( keyboard.getKeyValue(KeyboardConfig::KEY_SHORTCUT_1 + i)); graphics->setColor(Theme::getThemeColor(Theme::TEXT)); - g->drawText(key, state.x + 2, state.y + 2, gcn::Graphics::LEFT); + g->drawText(key, + state.x + skin.padding + 2, + state.y + skin.padding + 2, + gcn::Graphics::LEFT); - if (itemShortcut->getItem(i) < 0) + const int itemId = itemShortcut->getItem(i); + if (itemId < 0) continue; - Item *item = - PlayerInfo::getInventory()->findItem(itemShortcut->getItem(i)); - - if (item) + if (Item *item = PlayerInfo::getInventory()->findItem(itemId)) { // Draw item icon. if (Image *image = item->getImage()) @@ -83,11 +85,13 @@ void ItemShortcutContainer::draw(gcn::Graphics *graphics) caption = "Eq."; image->setAlpha(1.0f); - g->drawImage(image, state.x, state.y); + g->drawImage(image, state.x + skin.padding, state.y + skin.padding); if (item->isEquipped()) g->setColor(Theme::getThemeColor(Theme::ITEM_EQUIPPED)); - g->drawText(caption, state.x + mBoxWidth / 2, - state.y + mBoxHeight - 14, gcn::Graphics::CENTER); + g->drawText(caption, + state.x + mBoxWidth / 2, + state.y + mBoxHeight - 14, + gcn::Graphics::CENTER); } } } @@ -200,15 +204,7 @@ void ItemShortcutContainer::mouseReleased(gcn::MouseEvent &event) // Show ItemTooltip void ItemShortcutContainer::mouseMoved(gcn::MouseEvent &event) { - const int index = getIndexFromGrid(event.getX(), event.getY()); - if (index == -1) - return; - - const int itemId = itemShortcut->getItem(index); - if (itemId < 0) - return; - - if (Item *item = PlayerInfo::getInventory()->findItem(itemId)) + if (Item *item = getItemAt(event.getX(), event.getY())) { mItemPopup->setItem(item->getInfo()); mItemPopup->position(viewport->getMouseX(), viewport->getMouseY()); @@ -219,6 +215,19 @@ void ItemShortcutContainer::mouseMoved(gcn::MouseEvent &event) } } +Item *ItemShortcutContainer::getItemAt(int x, int y) const +{ + const int index = getIndexFromGrid(x, y); + if (index == -1) + return nullptr; + + const int itemId = itemShortcut->getItem(index); + if (itemId < 0) + return nullptr; + + return PlayerInfo::getInventory()->findItem(itemId); +} + // Hide ItemTooltip void ItemShortcutContainer::mouseExited(gcn::MouseEvent &event) { diff --git a/src/gui/widgets/itemshortcutcontainer.h b/src/gui/widgets/itemshortcutcontainer.h index 63d9e0ef..a01857db 100644 --- a/src/gui/widgets/itemshortcutcontainer.h +++ b/src/gui/widgets/itemshortcutcontainer.h @@ -67,6 +67,8 @@ class ItemShortcutContainer : public ShortcutContainer void mouseExited(gcn::MouseEvent &event) override; void mouseMoved(gcn::MouseEvent &event) override; + Item *getItemAt(int x, int y) const; + bool mItemClicked = false; Item *mItemMoved = nullptr; diff --git a/src/gui/widgets/label.cpp b/src/gui/widgets/label.cpp index a2ed8820..9c0fd3cd 100644 --- a/src/gui/widgets/label.cpp +++ b/src/gui/widgets/label.cpp @@ -21,8 +21,6 @@ #include "gui/widgets/label.h" -#include "textrenderer.h" - #include "resources/theme.h" #include <guichan/exception.hpp> @@ -59,15 +57,15 @@ void Label::draw(gcn::Graphics *graphics) throw GCN_EXCEPTION("Unknown alignment."); } - TextRenderer::renderText(static_cast<Graphics *>(graphics), - getCaption(), - textX, - textY, - getAlignment(), - getForegroundColor(), - getFont(), - mOutlineColor.has_value(), - mShadowColor.has_value(), - mOutlineColor, - mShadowColor); + auto g = static_cast<Graphics *>(graphics); + g->drawText(getCaption(), + textX, + textY, + getAlignment(), + getForegroundColor(), + getFont(), + mOutlineColor.has_value(), + mShadowColor.has_value(), + mOutlineColor, + mShadowColor); } diff --git a/src/gui/widgets/listbox.cpp b/src/gui/widgets/listbox.cpp index 112de232..612e785f 100644 --- a/src/gui/widgets/listbox.cpp +++ b/src/gui/widgets/listbox.cpp @@ -56,10 +56,14 @@ void ListBox::draw(gcn::Graphics *graphics) } // Draw the list elements - graphics->setColor(Theme::getThemeColor(Theme::TEXT)); for (int i = 0, y = 0; i < mListModel->getNumberOfElements(); ++i, y += height) { + if (mSelected == i) + graphics->setColor(Theme::getThemeColor(Theme::HIGHLIGHT_TEXT)); + else + graphics->setColor(Theme::getThemeColor(Theme::TEXT)); + graphics->drawText(mListModel->getElementAt(i), 1, y); } } diff --git a/src/gui/widgets/popup.cpp b/src/gui/widgets/popup.cpp index b245b9e6..c4c6f652 100644 --- a/src/gui/widgets/popup.cpp +++ b/src/gui/widgets/popup.cpp @@ -40,7 +40,7 @@ Popup::Popup(const std::string &name, SkinType skinType) , mMaxHeight(graphics->getHeight()) , mSkinType(skinType) { - logger->log("Popup::Popup(\"%s\")", name.c_str()); + Log::debug("Popup::Popup(\"%s\")", name.c_str()); if (!windowContainer) throw GCN_EXCEPTION("Popup::Popup(): no windowContainer set"); @@ -58,7 +58,7 @@ Popup::Popup(const std::string &name, SkinType skinType) Popup::~Popup() { - logger->log("Popup::~Popup(\"%s\")", mPopupName.c_str()); + Log::debug("Popup::~Popup(\"%s\")", mPopupName.c_str()); } void Popup::setWindowContainer(WindowContainer *wc) diff --git a/src/gui/widgets/progressbar.cpp b/src/gui/widgets/progressbar.cpp index 5cf1b05a..502ab686 100644 --- a/src/gui/widgets/progressbar.cpp +++ b/src/gui/widgets/progressbar.cpp @@ -83,11 +83,16 @@ void ProgressBar::draw(gcn::Graphics *graphics) rect.x = 0; rect.y = 0; + Theme::ProgressPalette palette = Theme::THEME_PROG_END; + if (mProgressPalette >= 0) + palette = static_cast<Theme::ProgressPalette>(mProgressPalette); + gui->getTheme()->drawProgressBar(static_cast<Graphics *>(graphics), rect, mColor, mProgress, - mText); + mText, + palette); } void ProgressBar::setProgress(float progress) diff --git a/src/gui/widgets/radiobutton.cpp b/src/gui/widgets/radiobutton.cpp index ceba78eb..3474bbd8 100644 --- a/src/gui/widgets/radiobutton.cpp +++ b/src/gui/widgets/radiobutton.cpp @@ -21,11 +21,11 @@ #include "gui/widgets/radiobutton.h" -#include "textrenderer.h" - #include "gui/gui.h" #include "resources/theme.h" +#include <guichan/font.hpp> + RadioButton::RadioButton(const std::string &caption, const std::string &group, bool marked) @@ -44,19 +44,19 @@ void RadioButton::draw(gcn::Graphics* graphics) if (isSelected()) widgetState.flags |= STATE_SELECTED; + auto g = static_cast<Graphics *>(graphics); auto &skin = gui->getTheme()->getSkin(SkinType::RadioButton); - skin.draw(static_cast<Graphics *>(graphics), widgetState); + skin.draw(g, widgetState); if (auto skinState = skin.getState(widgetState.flags)) { auto &textFormat = skinState->textFormat; - TextRenderer::renderText(static_cast<Graphics *>(graphics), - getCaption(), - skin.getMinWidth() + skin.padding + skin.spacing, - skin.padding, - Graphics::LEFT, - textFormat.bold ? boldFont : getFont(), - textFormat); + g->drawText(getCaption(), + skin.getMinWidth() + skin.padding + skin.spacing, + skin.padding, + Graphics::LEFT, + textFormat.bold ? boldFont : getFont(), + textFormat); } } diff --git a/src/gui/widgets/shoplistbox.cpp b/src/gui/widgets/shoplistbox.cpp index e2313c85..d745d74d 100644 --- a/src/gui/widgets/shoplistbox.cpp +++ b/src/gui/widgets/shoplistbox.cpp @@ -75,6 +75,7 @@ void ShopListBox::draw(gcn::Graphics *gcnGraphics) auto backgroundColor = Theme::getThemeColor(Theme::BACKGROUND); auto warningColor = Theme::getThemeColor(Theme::SHOP_WARNING); auto textColor = Theme::getThemeColor(Theme::TEXT); + auto highlightTextColor = Theme::getThemeColor(Theme::HIGHLIGHT_TEXT); highlightColor.a = alpha; backgroundColor.a = alpha; warningColor.a = alpha; @@ -136,7 +137,7 @@ void ShopListBox::draw(gcn::Graphics *gcnGraphics) } } - graphics->setColor(textColor); + graphics->setColor(i == mSelected ? highlightTextColor : textColor); graphics->drawText(mListModel->getElementAt(i), ITEM_ICON_SIZE + 5, y + (ITEM_ICON_SIZE - fontHeight) / 2); diff --git a/src/gui/widgets/tab.cpp b/src/gui/widgets/tab.cpp index b2779c4f..0f6ca4e5 100644 --- a/src/gui/widgets/tab.cpp +++ b/src/gui/widgets/tab.cpp @@ -73,18 +73,27 @@ void Tab::draw(gcn::Graphics *graphics) if (mTabbedArea && mTabbedArea->isTabSelected(this)) flags |= STATE_SELECTED; - auto &skin = gui->getTheme()->getSkin(SkinType::Tab); + auto theme = gui->getTheme(); + auto &palette = theme->getPalette(0); + auto &skin = theme->getSkin(SkinType::Tab); + if (auto state = skin.getState(flags)) { gcn::Color foregroundColor = state->textFormat.color; + auto outlineColor = state->textFormat.outlineColor; if (mFlash) - foregroundColor = Theme::getThemeColor(Theme::TAB_FLASH); + { + foregroundColor = palette.getColor(Theme::TAB_FLASH); + outlineColor = palette.getOutlineColor(Theme::TAB_FLASH); + } else if (mTabColor) + { foregroundColor = *mTabColor; + } auto label = static_cast<Label*>(mLabel); label->setForegroundColor(foregroundColor); - label->setOutlineColor(state->textFormat.outlineColor); + label->setOutlineColor(outlineColor); label->setShadowColor(state->textFormat.shadowColor); } diff --git a/src/gui/widgets/textbox.cpp b/src/gui/widgets/textbox.cpp index 6cc514fe..7fd7d626 100644 --- a/src/gui/widgets/textbox.cpp +++ b/src/gui/widgets/textbox.cpp @@ -23,7 +23,6 @@ #include "gui/gui.h" #include "resources/theme.h" -#include "textrenderer.h" #include <guichan/font.hpp> @@ -96,7 +95,7 @@ void TextBox::setTextWrapped(const std::string &text, int minDimension) xpos = width; wrappedStream << word; } - else if (xpos != 0 && xpos + getFont()->getWidth(" ") + width <= + else if (xpos != 0 && xpos + getFont()->getWidth(" ") + width <= mMinWidth) { xpos += getFont()->getWidth(" ") + width; @@ -176,18 +175,19 @@ void TextBox::draw(gcn::Graphics *graphics) graphics->setColor(*mTextColor); graphics->setFont(getFont()); + auto g = static_cast<Graphics*>(graphics); + for (i = 0; i < mTextRows.size(); i++) { // Move the text one pixel so we can have a caret before a letter. - TextRenderer::renderText(graphics, - mTextRows[i], - 1, - i * getFont()->getHeight(), - gcn::Graphics::LEFT, - *mTextColor, - getFont(), - mOutlineColor.has_value(), - false, - mOutlineColor); + g->drawText(mTextRows[i], + 1, + i * getFont()->getHeight(), + gcn::Graphics::LEFT, + *mTextColor, + getFont(), + mOutlineColor.has_value(), + false, + mOutlineColor); } } diff --git a/src/gui/widgets/textpreview.cpp b/src/gui/widgets/textpreview.cpp index 2f80bd23..aed04853 100644 --- a/src/gui/widgets/textpreview.cpp +++ b/src/gui/widgets/textpreview.cpp @@ -21,13 +21,7 @@ #include "gui/widgets/textpreview.h" -#include "configuration.h" -#include "textrenderer.h" - #include "gui/gui.h" -#include "gui/truetypefont.h" - -#include <typeinfo> TextPreview::TextPreview(const std::string &text) : mText(text) @@ -36,12 +30,13 @@ TextPreview::TextPreview(const std::string &text) mTextColor = &Theme::getThemeColor(Theme::TEXT); } -void TextPreview::draw(gcn::Graphics* graphics) +void TextPreview::draw(gcn::Graphics *graphics) { - TextRenderer::renderText(graphics, mText, 2, 2, gcn::Graphics::LEFT, - gcn::Color(mTextColor->r, - mTextColor->g, - mTextColor->b, - 255), - mFont, mOutline, mShadow); + auto g = static_cast<Graphics*>(graphics); + g->drawText(mText, 2, 2, gcn::Graphics::LEFT, + gcn::Color(mTextColor->r, + mTextColor->g, + mTextColor->b, + 255), + mFont, mOutline, mShadow); } diff --git a/src/gui/widgets/window.cpp b/src/gui/widgets/window.cpp index e57918b7..14d91af1 100644 --- a/src/gui/widgets/window.cpp +++ b/src/gui/widgets/window.cpp @@ -23,7 +23,6 @@ #include "configuration.h" #include "log.h" -#include "textrenderer.h" #include "gui/gui.h" #include "gui/viewport.h" @@ -53,7 +52,7 @@ Window::Window(SkinType skinType, const std::string &caption, bool modal, Window , mMaxWinWidth(graphics->getWidth()) , mMaxWinHeight(graphics->getHeight()) { - logger->log("Window::Window(\"%s\")", caption.c_str()); + Log::debug("Window::Window(\"%s\")", caption.c_str()); if (!windowContainer) throw GCN_EXCEPTION("Window::Window(): no windowContainer set"); @@ -82,7 +81,7 @@ Window::Window(SkinType skinType, const std::string &caption, bool modal, Window Window::~Window() { - logger->log("Window::~Window(\"%s\")", getCaption().c_str()); + Log::debug("Window::~Window(\"%s\")", getCaption().c_str()); saveWindowState(); @@ -139,13 +138,12 @@ void Window::drawFrame(gcn::Graphics *graphics) if (auto skinState = skin.getState(widgetState.flags)) { auto &textFormat = skinState->textFormat; - TextRenderer::renderText(g, - getCaption(), - getFrameSize() + skin.titleOffsetX, - getFrameSize() + skin.titleOffsetY, - gcn::Graphics::LEFT, - textFormat.bold ? boldFont : getFont(), - textFormat); + g->drawText(getCaption(), + getFrameSize() + skin.titleOffsetX, + getFrameSize() + skin.titleOffsetY, + gcn::Graphics::LEFT, + textFormat.bold ? boldFont : getFont(), + textFormat); } } } @@ -191,52 +189,6 @@ void Window::setLocationRelativeTo(gcn::Widget *widget) getY() + (wy + (widget->getHeight() - getHeight()) / 2 - y)); } -void Window::setLocationRelativeTo(ImageRect::ImagePosition position, - int offsetX, int offsetY) -{ - if (position == ImageRect::UPPER_LEFT) - { - } - else if (position == ImageRect::UPPER_CENTER) - { - offsetX += (graphics->getWidth() - getWidth()) / 2; - } - else if (position == ImageRect::UPPER_RIGHT) - { - offsetX += graphics->getWidth() - getWidth(); - } - else if (position == ImageRect::LEFT) - { - offsetY += (graphics->getHeight() - getHeight()) / 2; - } - else if (position == ImageRect::CENTER) - { - offsetX += (graphics->getWidth() - getWidth()) / 2; - offsetY += (graphics->getHeight() - getHeight()) / 2; - } - else if (position == ImageRect::RIGHT) - { - offsetX += graphics->getWidth() - getWidth(); - offsetY += (graphics->getHeight() - getHeight()) / 2; - } - else if (position == ImageRect::LOWER_LEFT) - { - offsetY += graphics->getHeight() - getHeight(); - } - else if (position == ImageRect::LOWER_CENTER) - { - offsetX += (graphics->getWidth() - getWidth()) / 2; - offsetY += graphics->getHeight() - getHeight(); - } - else if (position == ImageRect::LOWER_RIGHT) - { - offsetX += graphics->getWidth() - getWidth(); - offsetY += graphics->getHeight() - getHeight(); - } - - setPosition(offsetX, offsetY); -} - void Window::setMinWidth(int width) { mMinWinWidth = std::max(getSkin().getMinWidth(), width); @@ -599,41 +551,41 @@ void Window::setDefaultSize() } void Window::setDefaultSize(int defaultWidth, int defaultHeight, - ImageRect::ImagePosition position, + WindowAlignment alignment, int offsetX, int offsetY) { int x = 0; int y = 0; - switch (position) + switch (alignment) { - case ImageRect::UPPER_LEFT: + case WindowAlignment::TopLeft: break; - case ImageRect::UPPER_CENTER: + case WindowAlignment::Top: x = (graphics->getWidth() - defaultWidth) / 2; break; - case ImageRect::UPPER_RIGHT: + case WindowAlignment::TopRight: x = graphics->getWidth() - defaultWidth; break; - case ImageRect::LEFT: + case WindowAlignment::Left: y = (graphics->getHeight() - defaultHeight) / 2; break; - case ImageRect::CENTER: + case WindowAlignment::Center: x = (graphics->getWidth() - defaultWidth) / 2; y = (graphics->getHeight() - defaultHeight) / 2; break; - case ImageRect::RIGHT: + case WindowAlignment::Right: x = graphics->getWidth() - defaultWidth; y = (graphics->getHeight() - defaultHeight) / 2; break; - case ImageRect::LOWER_LEFT: + case WindowAlignment::BottomLeft: y = graphics->getHeight() - defaultHeight; break; - case ImageRect::LOWER_CENTER: + case WindowAlignment::Bottom: x = (graphics->getWidth() - defaultWidth) / 2; y = graphics->getHeight() - defaultHeight; break; - case ImageRect::LOWER_RIGHT: + case WindowAlignment::BottomRight: x = graphics->getWidth() - defaultWidth; y = graphics->getHeight() - defaultHeight; break; diff --git a/src/gui/widgets/window.h b/src/gui/widgets/window.h index 6331a715..2a47b0b9 100644 --- a/src/gui/widgets/window.h +++ b/src/gui/widgets/window.h @@ -36,6 +36,19 @@ class ResizeGrip; class Skin; class WindowContainer; +enum class WindowAlignment +{ + TopLeft, + Top, + TopRight, + Left, + Center, + Right, + BottomLeft, + Bottom, + BottomRight +}; + /** * A window. This window can be dragged around and has a title bar. Windows are * invisible by default. @@ -103,12 +116,6 @@ class Window : public gcn::Window, gcn::WidgetListener void setLocationRelativeTo(gcn::Widget *widget); /** - * Sets the location relative to the given enumerated position. - */ - void setLocationRelativeTo(ImageRect::ImagePosition position, - int offsetX = 0, int offsetY = 0); - - /** * Sets whether or not the window can be resized. */ void setResizable(bool resize); @@ -303,7 +310,7 @@ class Window : public gcn::Window, gcn::WidgetListener * on a relative enumerated position, rather than a coordinate position. */ void setDefaultSize(int defaultWidth, int defaultHeight, - ImageRect::ImagePosition position, + WindowAlignment alignment, int offsetx = 0, int offsetY = 0); /** diff --git a/src/gui/windowmenu.cpp b/src/gui/windowmenu.cpp index 0b2d126f..2c1b6211 100644 --- a/src/gui/windowmenu.cpp +++ b/src/gui/windowmenu.cpp @@ -23,9 +23,10 @@ #include "graphics.h" +#include "gui/abilitieswindow.h" #include "gui/emotepopup.h" +#include "gui/questswindow.h" #include "gui/skilldialog.h" -#include "gui/abilitieswindow.h" #include "gui/widgets/button.h" #include "gui/widgets/window.h" @@ -34,6 +35,8 @@ #include "net/net.h" #include "net/playerhandler.h" +#include "resources/questdb.h" + #include "utils/gettext.h" #include <string> @@ -64,6 +67,9 @@ WindowMenu::WindowMenu() if (abilitiesWindow->hasAbilities()) addButton(N_("Abilities"), x, h, "button-icon-abilities.png"); + if (QuestDB::hasQuests()) + addButton(N_("Quests"), x, h, "button-icon-quests.png"); + addButton(N_("Social"), x, h, "button-icon-social.png", KeyboardConfig::KEY_WINDOW_SOCIAL); addButton(N_("Shortcuts"), x, h, "button-icon-shortcut.png", @@ -122,6 +128,10 @@ void WindowMenu::action(const gcn::ActionEvent &event) { window = skillDialog; } + else if (event.getId() == "Quests") + { + window = questsWindow; + } else if (event.getId() == "Abilities") { window = abilitiesWindow; @@ -166,12 +176,18 @@ static std::string createShortcutCaption(const std::string &text, KeyboardConfig::KeyAction key) { std::string caption = gettext(text.c_str()); + if (key != KeyboardConfig::KEY_NO_VALUE) { - caption += " ("; - caption += SDL_GetKeyName(keyboard.getKeyValue(key)); - caption += ")"; + auto keyValue = keyboard.getKeyValue(key); + if (keyValue > 0) + { + caption += " ("; + caption += SDL_GetKeyName(keyValue); + caption += ")"; + } } + return caption; } @@ -179,7 +195,7 @@ void WindowMenu::addButton(const std::string &text, int &x, int &h, const std::string &iconPath, KeyboardConfig::KeyAction key) { - auto *btn = new Button("", text, this); + auto *btn = new Button(std::string(), text, this); if (!iconPath.empty() && btn->setButtonIcon(iconPath)) { btn->setButtonPopupText(createShortcutCaption(text, key)); @@ -187,7 +203,7 @@ void WindowMenu::addButton(const std::string &text, int &x, int &h, else { btn->setCaption(gettext(text.c_str())); - btn->setButtonPopupText(createShortcutCaption("", key)); + btn->setButtonPopupText(createShortcutCaption(std::string(), key)); } btn->setPosition(x, 0); @@ -204,40 +220,45 @@ void WindowMenu::updatePopUpCaptions() if (!button) continue; - std::string eventId = button->getActionEventId(); + const std::string &eventId = button->getActionEventId(); if (eventId == "Status") { - button->setButtonPopupText(createShortcutCaption("Status", + button->setButtonPopupText(createShortcutCaption(eventId, KeyboardConfig::KEY_WINDOW_STATUS)); } else if (eventId == "Equipment") { - button->setButtonPopupText(createShortcutCaption("Equipment", + button->setButtonPopupText(createShortcutCaption(eventId, KeyboardConfig::KEY_WINDOW_EQUIPMENT)); } else if (eventId == "Inventory") { - button->setButtonPopupText(createShortcutCaption("Inventory", + button->setButtonPopupText(createShortcutCaption(eventId, KeyboardConfig::KEY_WINDOW_INVENTORY)); } else if (eventId == "Skills") { - button->setButtonPopupText(createShortcutCaption("Skills", + button->setButtonPopupText(createShortcutCaption(eventId, KeyboardConfig::KEY_WINDOW_SKILL)); } + else if (eventId == "Quests") + { + button->setButtonPopupText( + createShortcutCaption(eventId, KeyboardConfig::KEY_WINDOW_QUESTS)); + } else if (eventId == "Social") { - button->setButtonPopupText(createShortcutCaption("Social", + button->setButtonPopupText(createShortcutCaption(eventId, KeyboardConfig::KEY_WINDOW_SOCIAL)); } else if (eventId == "Shortcuts") { - button->setButtonPopupText(createShortcutCaption("Shortcuts", + button->setButtonPopupText(createShortcutCaption(eventId, KeyboardConfig::KEY_WINDOW_SHORTCUT)); } else if (eventId == "Setup") { - button->setButtonPopupText(createShortcutCaption("Setup", + button->setButtonPopupText(createShortcutCaption(eventId, KeyboardConfig::KEY_WINDOW_SETUP)); } } diff --git a/src/inventory.cpp b/src/inventory.cpp index 51eb24e1..e45e094c 100644 --- a/src/inventory.cpp +++ b/src/inventory.cpp @@ -67,7 +67,7 @@ void Inventory::setItem(int index, int id, int quantity) { if (index < 0 || index >= getSize()) { - logger->log("Warning: invalid inventory index: %d", index); + Log::warn("Invalid inventory index: %d", index); return; } diff --git a/src/itemshortcut.cpp b/src/itemshortcut.cpp index 643a594f..4d2cec8a 100644 --- a/src/itemshortcut.cpp +++ b/src/itemshortcut.cpp @@ -29,8 +29,7 @@ ItemShortcut *itemShortcut; -ItemShortcut::ItemShortcut(): - mItemSelected(-1) +ItemShortcut::ItemShortcut() { load(); } @@ -42,8 +41,8 @@ ItemShortcut::~ItemShortcut() void ItemShortcut::load() { - for (int i = 0; i < SHORTCUT_ITEMS; i++) - mItems[i] = -1; + for (int &item : mItems) + item = -1; for (auto &shortcut : config.itemShortcuts) { diff --git a/src/itemshortcut.h b/src/itemshortcut.h index fcec3d7d..0849a8d1 100644 --- a/src/itemshortcut.h +++ b/src/itemshortcut.h @@ -109,7 +109,7 @@ class ItemShortcut void save(); int mItems[SHORTCUT_ITEMS]; /**< The items stored. */ - int mItemSelected; /**< The item held by cursor. */ + int mItemSelected = -1; /**< The item held by cursor. */ }; diff --git a/src/joystick.cpp b/src/joystick.cpp index c6e106bf..070e9dcf 100644 --- a/src/joystick.cpp +++ b/src/joystick.cpp @@ -36,9 +36,9 @@ void Joystick::init() SDL_JoystickEventState(SDL_ENABLE); joystickCount = SDL_NumJoysticks(); - logger->log("%i joysticks/gamepads found", joystickCount); + Log::info("%i joysticks/gamepads found", joystickCount); for (int i = 0; i < joystickCount; i++) - logger->log("- %s", SDL_JoystickNameForIndex(i)); + Log::info("- %s", SDL_JoystickNameForIndex(i)); } Joystick::Joystick(int no) @@ -57,14 +57,14 @@ Joystick::Joystick(int no) // TODO Bail out! if (!mJoystick) { - logger->log("Couldn't open joystick: %s", SDL_GetError()); + Log::info("Couldn't open joystick: %s", SDL_GetError()); return; } - logger->log("Axes: %i ", SDL_JoystickNumAxes(mJoystick)); - logger->log("Balls: %i", SDL_JoystickNumBalls(mJoystick)); - logger->log("Hats: %i", SDL_JoystickNumHats(mJoystick)); - logger->log("Buttons: %i", SDL_JoystickNumButtons(mJoystick)); + Log::info("Axes: %i ", SDL_JoystickNumAxes(mJoystick)); + Log::info("Balls: %i", SDL_JoystickNumBalls(mJoystick)); + Log::info("Hats: %i", SDL_JoystickNumHats(mJoystick)); + Log::info("Buttons: %i", SDL_JoystickNumButtons(mJoystick)); } Joystick::~Joystick() diff --git a/src/keyboardconfig.cpp b/src/keyboardconfig.cpp index ec5b5e37..92d37ace 100644 --- a/src/keyboardconfig.cpp +++ b/src/keyboardconfig.cpp @@ -71,6 +71,7 @@ static KeyData const keyData[KeyboardConfig::KEY_TOTAL] = { { "WindowInventory", SDLK_F3, _("Inventory Window") }, { "WindowEquipment", SDLK_F4, _("Equipment Window") }, { "WindowSkill", SDLK_F5, _("Skill Window") }, + { "WindowQuests", KeyboardConfig::KEY_NO_VALUE, _("Quest Window") }, { "WindowMinimap", SDLK_F6, _("Minimap Window") }, { "WindowChat", SDLK_F7, _("Chat Window") }, { "WindowShortcut", SDLK_F8, _("Item Shortcut Window") }, diff --git a/src/keyboardconfig.h b/src/keyboardconfig.h index 6fc79ced..be643b9b 100644 --- a/src/keyboardconfig.h +++ b/src/keyboardconfig.h @@ -32,9 +32,9 @@ */ struct KeyFunction { - const char* configField; /** Field index that is in the config file. */ - int defaultValue; /** The default key value used. */ - SDL_Keycode value; /** The actual value that is used. */ + const char* configField; /**< Field index that is in the config file. */ + int defaultValue; /**< The default key value used. */ + SDL_Keycode value; /**< The actual value that is used. */ }; class Setup_Keyboard; @@ -191,6 +191,7 @@ class KeyboardConfig KEY_WINDOW_INVENTORY, KEY_WINDOW_EQUIPMENT, KEY_WINDOW_SKILL, + KEY_WINDOW_QUESTS, KEY_WINDOW_MINIMAP, KEY_WINDOW_CHAT, KEY_WINDOW_SHORTCUT, diff --git a/src/log.cpp b/src/log.cpp index 24cb6e9d..eeb26b00 100644 --- a/src/log.cpp +++ b/src/log.cpp @@ -1,7 +1,7 @@ /* * The Mana Client * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2012 The Mana Developers + * Copyright (C) 2009-2025 The Mana Developers * * This file is part of The Mana Client. * @@ -23,47 +23,36 @@ #include <SDL.h> -#include <sys/time.h> +#include <cstdarg> +#include <fstream> #include <iostream> #include <sstream> -#include <cstdarg> -#include <cstdio> +#include <sys/time.h> -Logger::Logger() = default; -Logger::~Logger() = default; +static std::ofstream logFile; +static bool logToStandardOut = true; -void Logger::setLogFile(const std::string &logFilename) +static const char *getLogPriorityPrefix(SDL_LogPriority priority) { - mLogFile.open(logFilename, std::ios_base::trunc); - - if (!mLogFile.is_open()) - { - std::cout << "Warning: error while opening " << logFilename << - " for writing.\n"; + switch (priority) { + case SDL_LOG_PRIORITY_WARN: + return "Warning: "; + case SDL_LOG_PRIORITY_ERROR: + return "Error: "; + case SDL_LOG_PRIORITY_CRITICAL: + return "Critical Error: "; + default: + return ""; } } -void Logger::log(const char *log_text, ...) -{ - va_list ap; - va_start(ap, log_text); - vlog(log_text, ap); - va_end(ap); -} - -void Logger::vlog(const char *log_text, va_list ap) +static void logOutputFunction(void *userdata, int category, SDL_LogPriority priority, const char *message) { - const size_t bufSize = 1024; - char* buf = new char[bufSize]; - - // Use a temporary buffer to fill in the variables - vsnprintf(buf, bufSize, log_text, ap); - // Get the current system time timeval tv; gettimeofday(&tv, nullptr); - // Print the log entry + // Create timestamp string std::stringstream timeStr; timeStr << "[" << ((((tv.tv_sec / 60) / 60) % 24 < 10) ? "0" : "") @@ -79,24 +68,71 @@ void Logger::vlog(const char *log_text, va_list ap) << (int)((tv.tv_usec / 10000) % 100) << "] "; - if (mLogFile.is_open()) + const char *prefix = getLogPriorityPrefix(priority); + + if (logToStandardOut) + { + std::cout << timeStr.str() << prefix << message << std::endl; + } + + if (logFile.is_open()) { - mLogFile << timeStr.str() << buf << std::endl; + logFile << timeStr.str() << prefix << message << std::endl; } +} + +void Log::init() +{ + SDL_LogSetOutputFunction(logOutputFunction, nullptr); +} - if (mLogToStandardOut) +void Log::setLogFile(const std::string &logFilename) +{ + logFile.open(logFilename, std::ios_base::trunc); + + if (!logFile.is_open()) { - std::cout << timeStr.str() << buf << std::endl; + std::cout << "Warning: error while opening " << logFilename + << " for writing.\n"; } +} - // Delete temporary buffer - delete[] buf; +void Log::setLogToStandardOut(bool value) +{ + logToStandardOut = value; } -void Logger::error(const std::string &error_text) +#define DEFINE_LOG_FUNCTION(name, priority) \ + void Log::name(const char *fmt, ...) \ + { \ + va_list ap; \ + va_start(ap, fmt); \ + SDL_LogMessageV(SDL_LOG_CATEGORY_APPLICATION, priority, fmt, ap); \ + va_end(ap); \ + } + +DEFINE_LOG_FUNCTION(verbose, SDL_LOG_PRIORITY_VERBOSE) +DEFINE_LOG_FUNCTION(debug, SDL_LOG_PRIORITY_DEBUG) +DEFINE_LOG_FUNCTION(info, SDL_LOG_PRIORITY_INFO) +DEFINE_LOG_FUNCTION(warn, SDL_LOG_PRIORITY_WARN) +DEFINE_LOG_FUNCTION(error, SDL_LOG_PRIORITY_ERROR) + +#undef DEFINE_LOG_FUNCTION + +void Log::vinfo(const char *fmt, va_list ap) +{ + SDL_LogMessageV(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, fmt, ap); +} + +void Log::critical(const std::string &message) { - log("Error: %s", error_text.c_str()); - std::cerr << "Error: " << error_text << std::endl; - SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error", error_text.c_str(), nullptr); + SDL_LogCritical(SDL_LOG_CATEGORY_APPLICATION, "%s", message.c_str()); + + if (!logToStandardOut) + { + std::cerr << getLogPriorityPrefix(SDL_LOG_PRIORITY_CRITICAL) << message << std::endl; + } + + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error", message.c_str(), nullptr); exit(1); } @@ -1,7 +1,7 @@ /* * The Mana Client * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2012 The Mana Developers + * Copyright (C) 2009-2025 The Mana Developers * * This file is part of The Mana Client. * @@ -21,52 +21,51 @@ #pragma once -#include <fstream> +#include <string> +#include <cstdarg> + +#ifdef __GNUC__ +# define LOG_PRINTF_ATTR __attribute__((__format__(__printf__, 1, 2))) +#else +# define LOG_PRINTF_ATTR +#endif /** - * The Log Class : Useful to write debug or info messages + * The Log namespace: Useful to write debug or info messages to the log file + * and/or console. The messages will be timestamped. */ -class Logger +namespace Log { - public: - Logger(); + /** + * Initializes the log system. + */ + void init(); - /** - * Destructor, closes log file. - */ - ~Logger(); + /** + * Sets the file to log to and opens it. + */ + void setLogFile(const std::string &logFilename); - /** - * Sets the file to log to and opens it - */ - void setLogFile(const std::string &logFilename); + /** + * Sets whether the log should be written to standard output. + */ + void setLogToStandardOut(bool value); - /** - * Sets whether the log should be written to standard output. - */ - void setLogToStandardOut(bool value) { mLogToStandardOut = value; } - - /** - * Enters a message in the log. The message will be timestamped. - */ - void log(const char *log_text, ...) -#ifdef __GNUC__ - __attribute__((__format__(__printf__, 2, 3))) -#endif - ; + void verbose(const char *log_text, ...) LOG_PRINTF_ATTR; + void debug(const char *log_text, ...) LOG_PRINTF_ATTR; + void info(const char *log_text, ...) LOG_PRINTF_ATTR; + void warn(const char *log_text, ...) LOG_PRINTF_ATTR; + void error(const char *log_text, ...) LOG_PRINTF_ATTR; - void vlog(const char *log_text, va_list ap); + void vinfo(const char *log_text, va_list ap); - /** - * Log an error and quit. The error will be printed to standard error - * and showm in a simple message box. - */ - __attribute__((noreturn)) - void error(const std::string &error_text); + /** + * Log an error and quit. The error will be printed to standard error + * and shown in a simple message box. + */ + __attribute__((noreturn)) + void critical(const std::string &error_text); - private: - std::ofstream mLogFile; - bool mLogToStandardOut = true; -}; +} // namespace Log -extern Logger *logger; +#undef LOG_PRINTF_ATTR diff --git a/src/map.cpp b/src/map.cpp index 908d6178..8dbc7c28 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -983,7 +983,7 @@ void Map::addAnimation(int gid, TileAnimation animation) auto const [_, inserted] = mTileAnimations.try_emplace(gid, std::move(animation)); if (!inserted) { - logger->error(strprintf("Duplicate tile animation for gid %d", gid)); + Log::warn("Duplicate tile animation for gid %d", gid); } } diff --git a/src/net/download.cpp b/src/net/download.cpp index 7aab3b2f..571af7a4 100644 --- a/src/net/download.cpp +++ b/src/net/download.cpp @@ -108,13 +108,13 @@ bool Download::start() { assert(!mThread); // Download already started - logger->log("Starting download: %s", mUrl.c_str()); + Log::info("Starting download: %s", mUrl.c_str()); mThread = SDL_CreateThread(downloadThread, "Download", this); if (!mThread) { - logger->log("%s", DOWNLOAD_ERROR_MESSAGE_THREAD); + Log::info("%s", DOWNLOAD_ERROR_MESSAGE_THREAD); strncpy(mError, DOWNLOAD_ERROR_MESSAGE_THREAD, CURL_ERROR_SIZE - 1); mState.lock()->status = DownloadStatus::Error; return false; @@ -125,7 +125,7 @@ bool Download::start() void Download::cancel() { - logger->log("Canceling download: %s", mUrl.c_str()); + Log::info("Canceling download: %s", mUrl.c_str()); mCancel = true; } @@ -186,7 +186,7 @@ int Download::downloadThread(void *ptr) if (!curl) break; - logger->log("Downloading: %s", d->mUrl.c_str()); + Log::info("Downloading: %s", d->mUrl.c_str()); curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, d->mHeaders); @@ -236,8 +236,8 @@ int Download::downloadThread(void *ptr) if (res != CURLE_OK) { - logger->log("curl error %d: %s host: %s", - res, d->mError, d->mUrl.c_str()); + Log::info("curl error %d: %s host: %s", + res, d->mError, d->mUrl.c_str()); if (file) { @@ -262,9 +262,9 @@ int Download::downloadThread(void *ptr) // Remove the corrupted file ::remove(outFilename.c_str()); - logger->log("Checksum for file %s failed: (%lx/%lx)", - d->mFileName.c_str(), - adler, *d->mAdler); + Log::info("Checksum for file %s failed: (%lx/%lx)", + d->mFileName.c_str(), + adler, *d->mAdler); continue; // Bail out here to avoid the renaming } diff --git a/src/net/manaserv/charhandler.cpp b/src/net/manaserv/charhandler.cpp index 98591669..cc0ea17e 100644 --- a/src/net/manaserv/charhandler.cpp +++ b/src/net/manaserv/charhandler.cpp @@ -264,10 +264,10 @@ void CharHandler::handleCharacterSelectResponse(MessageIn &msg) chatServer.hostname.assign(msg.readString()); chatServer.port = msg.readInt16(); - logger->log("Game server: %s:%d", gameServer.hostname.c_str(), - gameServer.port); - logger->log("Chat server: %s:%d", chatServer.hostname.c_str(), - chatServer.port); + Log::info("Game server: %s:%d", gameServer.hostname.c_str(), + gameServer.port); + Log::info("Chat server: %s:%d", chatServer.hostname.c_str(), + chatServer.port); // Prevent the selected local player from being deleted local_player = mSelectedCharacter->dummy; diff --git a/src/net/manaserv/chathandler.cpp b/src/net/manaserv/chathandler.cpp index dca556c2..436da820 100644 --- a/src/net/manaserv/chathandler.cpp +++ b/src/net/manaserv/chathandler.cpp @@ -158,8 +158,8 @@ void ChatHandler::handleGameChatMessage(MessageIn &msg) if (!being) { - logger->log("Warning: Received GPMSG_SAY for unknown being with id %i." - " (Message is: %s)", id, chatMsg.c_str()); + Log::warn("Received GPMSG_SAY for unknown being with id %i." + " (Message is: %s)", id, chatMsg.c_str()); return; } @@ -262,7 +262,7 @@ void ChatHandler::handleChatMessage(MessageIn &msg) else { // Can't find channel - logger->log("Couldn't find chat channel id: %hi", channelId); + Log::info("Couldn't find chat channel id: %hi", channelId); } } diff --git a/src/net/manaserv/connection.cpp b/src/net/manaserv/connection.cpp index 1b6f757a..2eb5b4bf 100644 --- a/src/net/manaserv/connection.cpp +++ b/src/net/manaserv/connection.cpp @@ -44,13 +44,13 @@ Connection::~Connection() bool Connection::connect(const std::string &address, enet_uint16 port) { - logger->log("Net::Connection::connect(%s, %i)", address.c_str(), port); + Log::info("Net::Connection::connect(%s, %i)", address.c_str(), port); if (mConnection) disconnect(); if (address.empty()) { - logger->log("Net::Connection::connect() got empty address!"); + Log::info("Net::Connection::connect() got empty address!"); mState = NET_ERROR; return false; } @@ -65,7 +65,7 @@ bool Connection::connect(const std::string &address, enet_uint16 port) if (!mConnection) { - logger->log("Unable to initiate connection to the server."); + Log::info("Unable to initiate connection to the server."); mState = NET_ERROR; return false; } @@ -96,7 +96,7 @@ void Connection::send(const ManaServ::MessageOut &msg) { if (!isConnected()) { - logger->log("Warning: cannot send message to not connected server!"); + Log::warn("Cannot send message to not connected server!"); return; } diff --git a/src/net/manaserv/effecthandler.cpp b/src/net/manaserv/effecthandler.cpp index 22d1f9cf..afd7cd5c 100644 --- a/src/net/manaserv/effecthandler.cpp +++ b/src/net/manaserv/effecthandler.cpp @@ -82,7 +82,7 @@ void EffectHandler::handleCreateEffectBeing(MessageIn &msg) if (b) effectManager->trigger(eid, b); else - logger->log("Warning: CreateEffect called for unknown being #%d", bid); + Log::warn("CreateEffect called for unknown being #%d", bid); } void EffectHandler::handleCreateTextParticle(MessageIn &msg) @@ -120,7 +120,7 @@ void EffectHandler::handleShake(MessageIn &msg) viewport->shakeScreen(intensityX, intensityY, decay, duration); break; default: - logger->log("Warning: Received GPMSG_SHAKE message with unexpected length of %d bytes", msg.getUnreadLength()); + Log::warn("Received GPMSG_SHAKE message with unexpected length of %d bytes", msg.getUnreadLength()); } } diff --git a/src/net/manaserv/guildhandler.cpp b/src/net/manaserv/guildhandler.cpp index 9fdbafc2..bae38c37 100644 --- a/src/net/manaserv/guildhandler.cpp +++ b/src/net/manaserv/guildhandler.cpp @@ -73,7 +73,7 @@ void GuildHandler::handleMessage(MessageIn &msg) { case CPMSG_GUILD_CREATE_RESPONSE: { - logger->log("Received CPMSG_GUILD_CREATE_RESPONSE"); + Log::info("Received CPMSG_GUILD_CREATE_RESPONSE"); if (msg.readInt8() == ERRMSG_OK) { // TODO - Acknowledge guild was created @@ -88,7 +88,7 @@ void GuildHandler::handleMessage(MessageIn &msg) case CPMSG_GUILD_INVITE_RESPONSE: { - logger->log("Received CPMSG_GUILD_INVITE_RESPONSE"); + Log::info("Received CPMSG_GUILD_INVITE_RESPONSE"); const unsigned char response = msg.readInt8(); if (response == ERRMSG_OK) { @@ -111,7 +111,7 @@ void GuildHandler::handleMessage(MessageIn &msg) case CPMSG_GUILD_ACCEPT_RESPONSE: { - logger->log("Received CPMSG_GUILD_ACCEPT_RESPONSE"); + Log::info("Received CPMSG_GUILD_ACCEPT_RESPONSE"); if (msg.readInt8() == ERRMSG_OK) { // TODO - Acknowledge accepted into guild @@ -121,7 +121,7 @@ void GuildHandler::handleMessage(MessageIn &msg) case CPMSG_GUILD_GET_MEMBERS_RESPONSE: { - logger->log("Received CPMSG_GUILD_GET_MEMBERS_RESPONSE"); + Log::info("Received CPMSG_GUILD_GET_MEMBERS_RESPONSE"); if (msg.readInt8() == ERRMSG_OK) { std::string name; @@ -152,7 +152,7 @@ void GuildHandler::handleMessage(MessageIn &msg) case CPMSG_GUILD_UPDATE_LIST: { - logger->log("Received CPMSG_GUILD_UPDATE_LIST"); + Log::info("Received CPMSG_GUILD_UPDATE_LIST"); short guildId = msg.readInt16(); std::string name = msg.readString(); char eventId = msg.readInt8(); @@ -189,14 +189,14 @@ void GuildHandler::handleMessage(MessageIn &msg) break; default: - logger->log("Invalid guild event"); + Log::info("Invalid guild event"); } } } break; case CPMSG_GUILD_INVITED: { - logger->log("Received CPMSG_GUILD_INVITED"); + Log::info("Received CPMSG_GUILD_INVITED"); std::string inviterName = msg.readString(); std::string guildName = msg.readString(); int guildId = msg.readInt16(); @@ -207,7 +207,7 @@ void GuildHandler::handleMessage(MessageIn &msg) case CPMSG_GUILD_PROMOTE_MEMBER_RESPONSE: { - logger->log("Received CPMSG_GUILD_PROMOTE_MEMBER_RESPONSE"); + Log::info("Received CPMSG_GUILD_PROMOTE_MEMBER_RESPONSE"); if (msg.readInt8() == ERRMSG_OK) { @@ -223,14 +223,14 @@ void GuildHandler::handleMessage(MessageIn &msg) case CPMSG_GUILD_REJOIN: { - logger->log("Received CPMSG_GUILD_REJOIN"); + Log::info("Received CPMSG_GUILD_REJOIN"); joinedGuild(msg); } break; case CPMSG_GUILD_QUIT_RESPONSE: { - logger->log("Received CPMSG_GUILD_QUIT_RESPONSE"); + Log::info("Received CPMSG_GUILD_QUIT_RESPONSE"); if (msg.readInt8() == ERRMSG_OK) { @@ -247,7 +247,7 @@ void GuildHandler::handleMessage(MessageIn &msg) } break; case CPMSG_GUILD_KICK_NOTIFICATION: { - logger->log("Received CPMSG_GUILD_KICK_NOTIFICATION"); + Log::info("Received CPMSG_GUILD_KICK_NOTIFICATION"); const int guildId = msg.readInt16(); std::string player = msg.readString(); diff --git a/src/net/manaserv/inventoryhandler.cpp b/src/net/manaserv/inventoryhandler.cpp index 58a495af..fa31b32a 100644 --- a/src/net/manaserv/inventoryhandler.cpp +++ b/src/net/manaserv/inventoryhandler.cpp @@ -88,9 +88,8 @@ void EquipBackend::equip(int inventorySlot, int equipmentSlot) auto slotIt = mSlots.find(equipmentSlot); if (slotIt == mSlots.end()) { - logger->log("ManaServ::EquipBackend: Equipment slot %i" - " is not existing.", - equipmentSlot); + Log::info("ManaServ::EquipBackend: Equipment slot %i" + " is not existing.", equipmentSlot); return; } @@ -115,8 +114,8 @@ void EquipBackend::unequip(int inventorySlot) } } - logger->log("ManaServ::EquipBackend: No equipped item found at inventory " - "slot %i!", inventorySlot); + Log::info("ManaServ::EquipBackend: No equipped item found at inventory " + "slot %i!", inventorySlot); } void EquipBackend::event(Event::Channel, const Event &event) @@ -134,8 +133,8 @@ void EquipBackend::readEquipFile() if (!rootNode || rootNode.name() != "equip-slots") { - logger->log("ManaServ::EquipBackend: Error while reading " - EQUIP_FILE "!"); + Log::info("ManaServ::EquipBackend: Error while reading " + EQUIP_FILE "!"); return; } diff --git a/src/net/manaserv/loginhandler.cpp b/src/net/manaserv/loginhandler.cpp index 1c398990..9828af29 100644 --- a/src/net/manaserv/loginhandler.cpp +++ b/src/net/manaserv/loginhandler.cpp @@ -342,7 +342,7 @@ void LoginHandler::readServerInfo(MessageIn &msg) if (!updateHost.empty()) mLoginData->updateHost = updateHost; else - logger->log("Warning: server does not have an update host set!"); + Log::warn("Server does not have an update host set!"); // Read the client data folder for dynamic data loading. // This is only used by the Qt client. diff --git a/src/net/manaserv/network.cpp b/src/net/manaserv/network.cpp index d69d3397..cb9f76a0 100644 --- a/src/net/manaserv/network.cpp +++ b/src/net/manaserv/network.cpp @@ -48,14 +48,14 @@ void initialize() { if (enet_initialize()) { - logger->error("Failed to initialize ENet."); + Log::critical("Failed to initialize ENet."); } client = enet_host_create(nullptr, 3, 0, 0, 0); if (!client) { - logger->error("Failed to create the local host."); + Log::critical("Failed to create the local host."); } } @@ -66,7 +66,7 @@ void finalize() if (connections) { - logger->error("Tried to shutdown the network subsystem while there " + Log::critical("Tried to shutdown the network subsystem while there " "are network connections left!"); } @@ -78,7 +78,7 @@ Connection *getConnection() { if (!client) { - logger->error("Tried to instantiate a network object before " + Log::critical("Tried to instantiate a network object before " "initializing the network subsystem!"); } @@ -117,14 +117,14 @@ namespace if (iter != mMessageHandlers.end()) { - //logger->log("Received packet %x (%i B)", - // msg.getId(), msg.getLength()); + //Log::info("Received packet %x (%i B)", + // msg.getId(), msg.getLength()); iter->second->handleMessage(msg); } else { - logger->log("Unhandled packet %x (%i B)", - msg.getId(), msg.getLength()); + Log::info("Unhandled packet %x (%i B)", + msg.getId(), msg.getLength()); } // Clean up the packet now that we're done using it. @@ -142,7 +142,7 @@ void flush() switch (event.type) { case ENET_EVENT_TYPE_CONNECT: - logger->log("Connected to port %d.", event.peer->address.port); + Log::info("Connected to port %d.", event.peer->address.port); // Store any relevant server information here. event.peer->data = nullptr; break; @@ -152,7 +152,7 @@ void flush() break; case ENET_EVENT_TYPE_DISCONNECT: - logger->log("Disconnected."); + Log::info("Disconnected."); // Reset the server information. event.peer->data = nullptr; break; diff --git a/src/net/manaserv/partyhandler.cpp b/src/net/manaserv/partyhandler.cpp index e2a021cd..23ea7aa5 100644 --- a/src/net/manaserv/partyhandler.cpp +++ b/src/net/manaserv/partyhandler.cpp @@ -103,7 +103,7 @@ void PartyHandler::handleMessage(MessageIn &msg) "inviter has left the game.")); break; default: - logger->log("Unknown CPMSG_PARTY_INVITE_ANSWER_RESPONSE."); + Log::info("Unknown CPMSG_PARTY_INVITE_ANSWER_RESPONSE."); break; } } break; @@ -161,7 +161,7 @@ void PartyHandler::handleMessage(MessageIn &msg) name.c_str())); break; default: - logger->log("Unknown CPMSG_PARTY_REJECTED."); + Log::info("Unknown CPMSG_PARTY_REJECTED."); break; } } break; diff --git a/src/net/manaserv/playerhandler.cpp b/src/net/manaserv/playerhandler.cpp index 8ee9ed80..edae6be6 100644 --- a/src/net/manaserv/playerhandler.cpp +++ b/src/net/manaserv/playerhandler.cpp @@ -96,7 +96,7 @@ void PlayerHandler::handleMessage(MessageIn &msg) netToken = msg.readString(32); std::string address = msg.readString(); int port = msg.readInt16(); - logger->log("Changing server to %s:%d", address.c_str(), port); + Log::info("Changing server to %s:%d", address.c_str(), port); gameServer.hostname = address; gameServer.port = port; @@ -147,14 +147,14 @@ void PlayerHandler::handleMessage(MessageIn &msg) } break; case ATTRIBMOD_INVALID_ATTRIBUTE: { - logger->log("Warning: Server denied increase of attribute %d (unknown attribute) ", attrNum); + Log::warn("Server denied increase of attribute %d (unknown attribute) ", attrNum); } break; case ATTRIBMOD_NO_POINTS_LEFT: { // when the server says "you got no points" it // has to be correct. The server is always right! // undo attribute change and set points to 0 - logger->log("Warning: Server denied increase of attribute %d (no points left) ", attrNum); + Log::warn("Server denied increase of attribute %d (no points left) ", attrNum); int attrValue = PlayerInfo::getStatBase(attrNum) - 1; PlayerInfo::setAttribute(CHAR_POINTS, 0); PlayerInfo::setStatBase(attrNum, attrValue); @@ -162,7 +162,7 @@ void PlayerHandler::handleMessage(MessageIn &msg) case ATTRIBMOD_DENIED: { // undo attribute change - logger->log("Warning: Server denied increase of attribute %d (reason unknown) ", attrNum); + Log::warn("Server denied increase of attribute %d (reason unknown) ", attrNum); int points = PlayerInfo::getAttribute(CHAR_POINTS) - 1; PlayerInfo::setAttribute(CHAR_POINTS, points); @@ -184,14 +184,14 @@ void PlayerHandler::handleMessage(MessageIn &msg) } break; case ATTRIBMOD_INVALID_ATTRIBUTE: { - logger->log("Warning: Server denied reduction of attribute %d (unknown attribute) ", attrNum); + Log::warn("Server denied reduction of attribute %d (unknown attribute) ", attrNum); } break; case ATTRIBMOD_NO_POINTS_LEFT: { // when the server says "you got no points" it // has to be correct. The server is always right! // undo attribute change and set points to 0 - logger->log("Warning: Server denied reduction of attribute %d (no points left) ", attrNum); + Log::warn("Server denied reduction of attribute %d (no points left) ", attrNum); int attrValue = PlayerInfo::getStatBase(attrNum) + 1; // TODO are these right? PlayerInfo::setAttribute(CHAR_POINTS, 0); @@ -201,7 +201,7 @@ void PlayerHandler::handleMessage(MessageIn &msg) case ATTRIBMOD_DENIED: { // undo attribute change - logger->log("Warning: Server denied reduction of attribute %d (reason unknown) ", attrNum); + Log::warn("Server denied reduction of attribute %d (reason unknown) ", attrNum); int charaPoints = PlayerInfo::getAttribute(CHAR_POINTS) - 1; PlayerInfo::setAttribute(CHAR_POINTS, charaPoints); @@ -245,7 +245,7 @@ void PlayerHandler::handleMessage(MessageIn &msg) BY_SERVER); break; default: - logger->log("0x013b: Unhandled message %i", type); + Log::info("0x013b: Unhandled message %i", type); break; } } @@ -263,7 +263,7 @@ void PlayerHandler::handleMapChangeMessage(MessageIn &msg) Game *game = Game::instance(); const bool sameMap = (game->getCurrentMapName() == mapName); - logger->log("Changing map to %s (%d, %d)", mapName.c_str(), x, y); + Log::info("Changing map to %s (%d, %d)", mapName.c_str(), x, y); // Switch the actual map, deleting the previous one game->changeMap(mapName); @@ -285,8 +285,8 @@ void PlayerHandler::handleMapChangeMessage(MessageIn &msg) local_player->setPosition(x, y); local_player->setDestination(x, y); - logger->log("Adjust scrolling by %d,%d", (int) scrollOffsetX, - (int) scrollOffsetY); + Log::info("Adjust scrolling by %d,%d", (int) scrollOffsetX, + (int) scrollOffsetY); viewport->scrollBy(scrollOffsetX, scrollOffsetY); } @@ -295,7 +295,7 @@ void PlayerHandler::attack(int id) auto ability = AbilityDB::find("Strike"); if (!ability) { - logger->log("PlayerHandler::attack: 'Strike' ability not found."); + Log::info("PlayerHandler::attack: 'Strike' ability not found."); return; } @@ -304,7 +304,7 @@ void PlayerHandler::attack(int id) abilityHandler->useOn(ability->id, id); break; case AbilityInfo::TARGET_POINT: - logger->log("PlayerHandler::attack: Unsupported target mode 'point' for 'Strike' ability."); + Log::info("PlayerHandler::attack: Unsupported target mode 'point' for 'Strike' ability."); break; case AbilityInfo::TARGET_DIRECTION: abilityHandler->useInDirection(ability->id, local_player->getDirection()); @@ -420,8 +420,8 @@ Vector PlayerHandler::getPixelsPerSecondMoveSpeed(const Vector &speed, Map *map) if (!map) { - logger->log("Manaserv::PlayerHandler: Speed wasn't given back" - " because Map not initialized."); + Log::info("Manaserv::PlayerHandler: Speed wasn't given back" + " because Map not initialized."); return speedInPixels; } diff --git a/src/net/net.cpp b/src/net/net.cpp index 1d157b3d..443a739c 100644 --- a/src/net/net.cpp +++ b/src/net/net.cpp @@ -138,7 +138,7 @@ void connectToServer(ServerInfo &server) else if (server.port == 9601) server.type = ServerType::ManaServ; else - logger->error(_("Unknown Server Type! Exiting.")); + Log::critical(_("Unknown Server Type! Exiting.")); } if (networkType == server.type && getGeneralHandler() != nullptr) @@ -160,7 +160,7 @@ void connectToServer(ServerInfo &server) generalHandler = new TmwAthena::GeneralHandler; break; default: - logger->error(_("Server protocol unsupported")); + Log::critical(_("Server protocol unsupported")); break; } @@ -203,4 +203,3 @@ ServerType getNetworkType() } } // namespace Net - diff --git a/src/net/playerhandler.h b/src/net/playerhandler.h index b9cf1abf..e5b86b2e 100644 --- a/src/net/playerhandler.h +++ b/src/net/playerhandler.h @@ -24,6 +24,8 @@ #include "being.h" #include "flooritem.h" +#include "resources/questdb.h" + namespace Net { class PlayerHandler @@ -80,6 +82,11 @@ class PlayerHandler * Return false when tiles-center positions only are to be used. */ virtual bool usePixelPrecision() = 0; + + const QuestVars &getQuestVars() const { return mQuestVars; } + + protected: + QuestVars mQuestVars; }; } // namespace Net diff --git a/src/net/tmwa/abilityhandler.cpp b/src/net/tmwa/abilityhandler.cpp index ab891b40..fea492ef 100644 --- a/src/net/tmwa/abilityhandler.cpp +++ b/src/net/tmwa/abilityhandler.cpp @@ -129,7 +129,7 @@ void AbilityHandler::handleMessage(MessageIn &msg) auto type = msg.readInt8(); if (btype == BSKILL_EMOTE) { - logger->log("Action: %d", btype); + Log::info("Action: %d", btype); } std::string msg; diff --git a/src/net/tmwa/beinghandler.cpp b/src/net/tmwa/beinghandler.cpp index c5979e9f..690b0d87 100644 --- a/src/net/tmwa/beinghandler.cpp +++ b/src/net/tmwa/beinghandler.cpp @@ -33,9 +33,9 @@ #include "playerrelations.h" #include "net/net.h" -#include "net/playerhandler.h" #include "net/tmwa/messagein.h" #include "net/tmwa/messageout.h" +#include "net/tmwa/playerhandler.h" #include "net/tmwa/protocol.h" #include "resources/emotedb.h" @@ -107,6 +107,12 @@ static Being *createBeing(int id, short job) outMsg.writeInt32(id); } + if (type == ActorSprite::NPC) + { + auto playerHandler = static_cast<TmwAthena::PlayerHandler*>(Net::getPlayerHandler()); + playerHandler->applyQuestStatusEffects(being); + } + return being; } @@ -525,8 +531,8 @@ void BeingHandler::handleMessage(MessageIn &msg) dstBeing->setSprite(SPRITE_MISC2, id); break; default: - logger->log("SMSG_BEING_CHANGE_LOOKS2: unsupported type: " - "%d, id: %d", static_cast<int>(type), id); + Log::info("SMSG_BEING_CHANGE_LOOKS2: unsupported type: " + "%d, id: %d", static_cast<int>(type), id); break; } } diff --git a/src/net/tmwa/buysellhandler.cpp b/src/net/tmwa/buysellhandler.cpp index 1fdf1ffe..d7acd674 100644 --- a/src/net/tmwa/buysellhandler.cpp +++ b/src/net/tmwa/buysellhandler.cpp @@ -99,7 +99,7 @@ void BuySellHandler::handleMessage(MessageIn &msg) Item *item = PlayerInfo::getInventory()->getItem(index); - if (item && !(item->isEquipped())) + if (item && !item->isEquipped()) dialog->addItem(item, value); } } diff --git a/src/net/tmwa/charserverhandler.cpp b/src/net/tmwa/charserverhandler.cpp index 0ecbb135..fcd47b74 100644 --- a/src/net/tmwa/charserverhandler.cpp +++ b/src/net/tmwa/charserverhandler.cpp @@ -89,8 +89,8 @@ void CharServerHandler::handleMessage(MessageIn &msg) auto *character = new Net::Character; readPlayerData(msg, character); mCharacters.push_back(character); - logger->log("CharServer: Player: %s (%d)", - character->dummy->getName().c_str(), character->slot); + Log::info("CharServer: Player: %s (%d)", + character->dummy->getName().c_str(), character->slot); } Client::setState(STATE_CHAR_SELECT); diff --git a/src/net/tmwa/gamehandler.cpp b/src/net/tmwa/gamehandler.cpp index 0a3bb9d9..a88e377e 100644 --- a/src/net/tmwa/gamehandler.cpp +++ b/src/net/tmwa/gamehandler.cpp @@ -68,8 +68,8 @@ void GameHandler::handleMessage(MessageIn &msg) msg.readInt32(); // server tick msg.readCoordinates(x, y, direction); msg.skip(2); // unknown - logger->log("Protocol: Player start position: (%d, %d), Direction: %d", - x, y, direction); + Log::info("Protocol: Player start position: (%d, %d), Direction: %d", + x, y, direction); // Switch now or we'll have problems Client::setState(STATE_GAME); // Stores the position until the map is loaded. diff --git a/src/net/tmwa/generalhandler.cpp b/src/net/tmwa/generalhandler.cpp index d6eb3b34..1f52c3db 100644 --- a/src/net/tmwa/generalhandler.cpp +++ b/src/net/tmwa/generalhandler.cpp @@ -117,7 +117,7 @@ void GeneralHandler::handleMessage(MessageIn &msg) { case SMSG_CONNECTION_PROBLEM: code = msg.readInt8(); - logger->log("Connection problem: %i", code); + Log::info("Connection problem: %i", code); switch (code) { diff --git a/src/net/tmwa/inventoryhandler.cpp b/src/net/tmwa/inventoryhandler.cpp index 0d8e3005..73d967a6 100644 --- a/src/net/tmwa/inventoryhandler.cpp +++ b/src/net/tmwa/inventoryhandler.cpp @@ -157,10 +157,10 @@ void InventoryHandler::handleMessage(MessageIn &msg) if (debugInventory) { - logger->log("Index: %d, ID: %d, Type: %d, Identified: %d, " - "Qty: %d, Cards: %d, %d, %d, %d", - index, itemId, itemType, identified, amount, - cards[0], cards[1], cards[2], cards[3]); + Log::info("Index: %d, ID: %d, Type: %d, Identified: %d, " + "Qty: %d, Cards: %d, %d, %d, %d", + index, itemId, itemType, identified, amount, + cards[0], cards[1], cards[2], cards[3]); } if (msg.getId() == SMSG_PLAYER_INVENTORY) @@ -191,10 +191,10 @@ void InventoryHandler::handleMessage(MessageIn &msg) if (debugInventory) { - logger->log("Index: %d, ID: %d, Type: %d, Identified: %d, " - "Qty: %d, Cards: %d, %d, %d, %d", - index, itemId, itemType, identified, amount, - cards[0], cards[1], cards[2], cards[3]); + Log::info("Index: %d, ID: %d, Type: %d, Identified: %d, " + "Qty: %d, Cards: %d, %d, %d, %d", + index, itemId, itemType, identified, amount, + cards[0], cards[1], cards[2], cards[3]); } mInventoryItems.push_back( @@ -419,8 +419,8 @@ void InventoryHandler::handleMessage(MessageIn &msg) } else { - logger->log("Couldn't set attacke range due to the lack" - "of an initialized map."); + Log::info("Couldn't set attacke range due to the lack" + "of an initialized map."); local_player->setAttackRange(-1); } } @@ -434,7 +434,7 @@ void InventoryHandler::handleMessage(MessageIn &msg) index -= INVENTORY_OFFSET; - logger->log("Arrows equipped: %i", index); + Log::info("Arrows equipped: %i", index); mEquips.setEquipment(EQUIP_PROJECTILE_SLOT, index); break; } diff --git a/src/net/tmwa/inventoryhandler.h b/src/net/tmwa/inventoryhandler.h index f5ef4492..cde1235b 100644 --- a/src/net/tmwa/inventoryhandler.h +++ b/src/net/tmwa/inventoryhandler.h @@ -108,9 +108,9 @@ class EquipBackend final : public Equipment::Backend if (!newItem && inventoryIndex >= 0) { - logger->log("EquipBackend: Warning, trying to equip " - "non-existing item from inventory index %i at " - "equipment slot %i.", inventoryIndex, index); + Log::info("EquipBackend: Warning, trying to equip " + "non-existing item from inventory index %i at " + "equipment slot %i.", inventoryIndex, index); return; } diff --git a/src/net/tmwa/loginhandler.cpp b/src/net/tmwa/loginhandler.cpp index a7162ee6..b6e3d518 100644 --- a/src/net/tmwa/loginhandler.cpp +++ b/src/net/tmwa/loginhandler.cpp @@ -108,7 +108,7 @@ void LoginHandler::handleMessage(MessageIn &msg) mUpdateHost = msg.readString(len); loginData.updateHost = mUpdateHost; - logger->log("Received update host \"%s\" from login server.", + Log::info("Received update host \"%s\" from login server.", mUpdateHost.c_str()); break; } @@ -138,10 +138,10 @@ void LoginHandler::handleMessage(MessageIn &msg) msg.readInt16(); // maintenance msg.readInt16(); // is_new - logger->log("Network: Server: %s (%s:%d)", - world->name.c_str(), - ipToString(world->address), - world->port); + Log::info("Network: Server: %s (%s:%d)", + world->name.c_str(), + ipToString(world->address), + world->port); mWorlds.push_back(world); } @@ -150,7 +150,7 @@ void LoginHandler::handleMessage(MessageIn &msg) case SMSG_LOGIN_ERROR: code = msg.readInt8(); - logger->log("Login::error code: %i", code); + Log::info("Login::error code: %i", code); switch (code) { @@ -212,9 +212,9 @@ void LoginHandler::handleMessage(MessageIn &msg) mServerVersion = 0; if (mServerVersion > 0) - logger->log("TMW server version: x%06x", mServerVersion); + Log::info("TMW server version: x%06x", mServerVersion); else - logger->log("Server without version"); + Log::info("Server without version"); mRegistrationEnabled = (options & FLAG_REGISTRATION); diff --git a/src/net/tmwa/messagein.cpp b/src/net/tmwa/messagein.cpp index c0db0fca..2630c511 100644 --- a/src/net/tmwa/messagein.cpp +++ b/src/net/tmwa/messagein.cpp @@ -26,9 +26,11 @@ #include <SDL_endian.h> +#ifndef MAKEWORD #define MAKEWORD(low,high) \ ((unsigned short)(((unsigned char)(low)) | \ ((unsigned short)((unsigned char)(high))) << 8)) +#endif namespace TmwAthena { diff --git a/src/net/tmwa/messageout.cpp b/src/net/tmwa/messageout.cpp index a886fb4d..7758e306 100644 --- a/src/net/tmwa/messageout.cpp +++ b/src/net/tmwa/messageout.cpp @@ -23,6 +23,8 @@ #include "net/tmwa/network.h" +#include "log.h" + #include <SDL_endian.h> #include <cstring> @@ -32,7 +34,7 @@ namespace TmwAthena { MessageOut::MessageOut(uint16_t id) { #ifdef DEBUG - logger->log("Sending %s (0x%x)", Network::mInstance->messageName(id), id); + Log::info("Sending %s (0x%x)", Network::mInstance->messageName(id), id); #endif writeInt16(id); } diff --git a/src/net/tmwa/network.cpp b/src/net/tmwa/network.cpp index b448dc4f..9e010f7c 100644 --- a/src/net/tmwa/network.cpp +++ b/src/net/tmwa/network.cpp @@ -279,7 +279,7 @@ bool Network::connect(const ServerInfo &server) { if (mState != IDLE && mState != NET_ERROR) { - logger->log("Tried to connect an already connected socket!"); + Log::info("Tried to connect an already connected socket!"); assert(false); return false; } @@ -290,8 +290,8 @@ bool Network::connect(const ServerInfo &server) return false; } - logger->log("Network::Connecting to %s:%i", server.hostname.c_str(), - server.port); + Log::info("Network::Connecting to %s:%i", server.hostname.c_str(), + server.port); mServer.hostname = server.hostname; mServer.port = server.port; @@ -376,8 +376,7 @@ void Network::dispatchMessages() auto packetInfoIt = mPacketInfo.find(msgId); if (packetInfoIt == mPacketInfo.end()) { - auto error = strprintf("Unknown packet 0x%x received.", msgId); - logger->error(error); + Log::critical(strprintf("Unknown packet 0x%x received.", msgId)); break; } @@ -395,9 +394,8 @@ void Network::dispatchMessages() if (len < 4) { - auto error = strprintf("Variable length packet 0x%x has invalid length %d.", - msgId, len); - logger->error(error); + Log::critical(strprintf("Variable length packet 0x%x has invalid length %d.", + msgId, len)); break; } } @@ -413,14 +411,14 @@ void Network::dispatchMessages() if (iter != mMessageHandlers.end()) { #ifdef DEBUG - logger->log("Handling %s (0x%x) of length %d", packetInfo->name, msgId, len); + Log::info("Handling %s (0x%x) of length %d", packetInfo->name, msgId, len); #endif iter->second->handleMessage(message); } else { - logger->log("Unhandled %s (0x%x) of length %d", packetInfo->name, msgId, len); + Log::info("Unhandled %s (0x%x) of length %d", packetInfo->name, msgId, len); } skip(len); @@ -474,7 +472,7 @@ bool Network::realConnect() std::string errorMessage = strprintf(_("Unable to resolve host \"%s\""), mServer.hostname.c_str()); setError(errorMessage); - logger->log("SDLNet_ResolveHost: %s", errorMessage.c_str()); + Log::info("SDLNet_ResolveHost: %s", errorMessage.c_str()); return false; } @@ -483,13 +481,13 @@ bool Network::realConnect() mSocket = SDLNet_TCP_Open(&ipAddress); if (!mSocket) { - logger->log("Error in SDLNet_TCP_Open(): %s", SDLNet_GetError()); + Log::info("Error in SDLNet_TCP_Open(): %s", SDLNet_GetError()); setError(SDLNet_GetError()); return false; } - logger->log("Network::Started session with %s:%i", - ipToString(ipAddress.host), ipAddress.port); + Log::info("Network::Started session with %s:%i", + ipToString(ipAddress.host), ipAddress.port); mState = CONNECTED; @@ -522,7 +520,7 @@ void Network::receive() switch (numReady) { case -1: - logger->log("Error: SDLNet_CheckSockets"); + Log::error("SDLNet_CheckSockets"); // FALLTHROUGH case 0: break; @@ -537,7 +535,7 @@ void Network::receive() { // We got disconnected mState = IDLE; - logger->log("Disconnected."); + Log::info("Disconnected."); } else if (ret < 0) { @@ -578,7 +576,7 @@ void Network::receive() if (SDLNet_TCP_DelSocket(set, mSocket) == -1) { - logger->log("Error in SDLNet_DelSocket(): %s", SDLNet_GetError()); + Log::info("Error in SDLNet_DelSocket(): %s", SDLNet_GetError()); } SDLNet_FreeSocketSet(set); @@ -586,7 +584,7 @@ void Network::receive() void Network::setError(const std::string &error) { - logger->log("Network error: %s", error.c_str()); + Log::info("Network error: %s", error.c_str()); mError = error; mState = NET_ERROR; } diff --git a/src/net/tmwa/partyhandler.cpp b/src/net/tmwa/partyhandler.cpp index 2b256cd5..78dfd7a0 100644 --- a/src/net/tmwa/partyhandler.cpp +++ b/src/net/tmwa/partyhandler.cpp @@ -184,7 +184,7 @@ void PartyHandler::handleMessage(MessageIn &msg) partyTab->chatLog(_("Experience sharing not possible."), BY_SERVER); break; default: - logger->log("Unknown party exp option: %d", exp); + Log::info("Unknown party exp option: %d", exp); } switch (item) @@ -208,7 +208,7 @@ void PartyHandler::handleMessage(MessageIn &msg) partyTab->chatLog(_("Item sharing not possible."), BY_SERVER); break; default: - logger->log("Unknown party item option: %d", exp); + Log::info("Unknown party item option: %d", exp); } break; } diff --git a/src/net/tmwa/playerhandler.cpp b/src/net/tmwa/playerhandler.cpp index f6f6ef41..44b0efd3 100644 --- a/src/net/tmwa/playerhandler.cpp +++ b/src/net/tmwa/playerhandler.cpp @@ -21,8 +21,11 @@ #include "net/tmwa/playerhandler.h" +#include "actorspritemanager.h" +#include "being.h" #include "client.h" #include "configuration.h" +#include "effectmanager.h" #include "game.h" #include "localplayer.h" #include "log.h" @@ -55,7 +58,7 @@ const int MAP_TELEPORT_SCROLL_DISTANCE = 8; namespace { /** - * Listener used for handling the overweigth message. + * Listener used for handling the overweight message. */ struct WeightListener : public gcn::ActionListener { @@ -126,7 +129,7 @@ static const char *randomDeathMessage() N_("You're off the twig."), N_("You've kicked the bucket."), N_("You've shuffled off your mortal coil, run down the " - "curtain and joined the bleedin' choir invisibile."), + "curtain and joined the bleedin' choir invisible."), N_("You are an ex-player."), N_("You're pining for the fjords.") }; @@ -152,10 +155,14 @@ PlayerHandler::PlayerHandler() SMSG_PLAYER_STAT_UPDATE_6, SMSG_PLAYER_ARROW_MESSAGE, SMSG_MAP_MASK, + SMSG_QUEST_SET_VAR, + SMSG_QUEST_PLAYER_VARS, 0 }; handledMessages = _messages; playerHandler = this; + + listen(Event::GameChannel); } void PlayerHandler::handleMessage(MessageIn &msg) @@ -179,7 +186,7 @@ void PlayerHandler::handleMessage(MessageIn &msg) int x = msg.readInt16(); int y = msg.readInt16(); - logger->log("Warping to %s (%d, %d)", mapPath.c_str(), x, y); + Log::info("Warping to %s (%d, %d)", mapPath.c_str(), x, y); /* * We must clear the local player's target *before* the call @@ -217,8 +224,8 @@ void PlayerHandler::handleMessage(MessageIn &msg) // Stop movement local_player->setDestination(pos.x, pos.y); - logger->log("Adjust scrolling by %d:%d", (int) scrollOffsetX, - (int) scrollOffsetY); + Log::info("Adjust scrolling by %d:%d", (int) scrollOffsetX, + (int) scrollOffsetY); viewport->scrollBy(scrollOffsetX, scrollOffsetY); } @@ -499,7 +506,7 @@ void PlayerHandler::handleMessage(MessageIn &msg) serverNotice(_("Equip arrows first.")); break; default: - logger->log("0x013b: Unhandled message %i", type); + Log::info("0x013b: Unhandled message %i", type); break; } } @@ -514,6 +521,49 @@ void PlayerHandler::handleMessage(MessageIn &msg) map->setMask(mask); } break; + + case SMSG_QUEST_SET_VAR: + { + int variable = msg.readInt16(); + int value = msg.readInt32(); + int oldValue = mQuestVars.get(variable); + + mQuestVars.set(variable, value); + updateQuestStatusEffects(); + Event::trigger(Event::QuestsChannel, Event::QuestVarsChanged); + + if (effectManager && local_player) + { + switch (QuestDB::questChange(variable, oldValue, value)) + { + case QuestChange::None: + break; + case QuestChange::New: + effectManager->trigger(paths.getIntValue("newQuestEffectId"), local_player); + break; + case QuestChange::Completed: + effectManager->trigger(paths.getIntValue("completeQuestEffectId"), local_player); + break; + } + } + break; + } + + case SMSG_QUEST_PLAYER_VARS: + { + msg.readInt16(); // length + mQuestVars.clear(); + unsigned int count = (msg.getLength() - 4) / 6; + for (unsigned int i = 0; i < count; ++i) + { + int variable = msg.readInt16(); + int value = msg.readInt32(); + mQuestVars.set(variable, value); + } + updateQuestStatusEffects(); + Event::trigger(Event::QuestsChannel, Event::QuestVarsChanged); + break; + } } } @@ -649,8 +699,8 @@ Vector PlayerHandler::getPixelsPerSecondMoveSpeed(const Vector &speed, Map *map) if (!map || speed.x == 0 || speed.y == 0) { - logger->log("TmwAthena::PlayerHandler: Speed set to default: " - "Map not yet initialized or invalid speed."); + Log::info("TmwAthena::PlayerHandler: Speed set to default: " + "Map not yet initialized or invalid speed."); return getDefaultMoveSpeed(); } @@ -664,4 +714,54 @@ Vector PlayerHandler::getPixelsPerSecondMoveSpeed(const Vector &speed, Map *map) return pixelsPerSecond; } +void PlayerHandler::event(Event::Channel channel, const Event &event) +{ + if (channel == Event::GameChannel) + { + if (event.getType() == Event::MapLoaded) + { + updateQuestStatusEffects(); + } + } +} + +void PlayerHandler::applyQuestStatusEffects(Being *npc) +{ + const auto npcId = npc->getSubType(); + const auto effect = mActiveQuestEffects.get(npcId); + if (effect != 0) + npc->setStatusEffect(effect, true); +} + +void PlayerHandler::updateQuestStatusEffects() +{ + auto game = Game::instance(); + if (!game) + return; + + const auto ¤tMapName = game->getCurrentMapName(); + auto updatedQuestEffects = QuestDB::getActiveEffects(mQuestVars, currentMapName); + + // Loop over all NPCs, disabling no longer active effects and enabling new ones + for (auto actor : actorSpriteManager->getAll()) { + if (actor->getType() != ActorSprite::NPC) + continue; + + auto *npc = static_cast<Being *>(actor); + const auto npcId = npc->getSubType(); + const auto oldEffect = mActiveQuestEffects.get(npcId); + const auto newEffect = updatedQuestEffects.get(npcId); + + if (oldEffect != newEffect) + { + if (oldEffect != 0) + npc->setStatusEffect(oldEffect, false); + if (newEffect != 0) + npc->setStatusEffect(newEffect, true); + } + } + + std::swap(mActiveQuestEffects, updatedQuestEffects); +} + } // namespace TmwAthena diff --git a/src/net/tmwa/playerhandler.h b/src/net/tmwa/playerhandler.h index f1a67e94..49990d85 100644 --- a/src/net/tmwa/playerhandler.h +++ b/src/net/tmwa/playerhandler.h @@ -28,7 +28,8 @@ namespace TmwAthena { -class PlayerHandler final : public MessageHandler, public Net::PlayerHandler +class PlayerHandler final : public MessageHandler, public Net::PlayerHandler, + public EventListener { public: PlayerHandler(); @@ -63,6 +64,16 @@ class PlayerHandler final : public MessageHandler, public Net::PlayerHandler bool usePixelPrecision() override { return false; } + + // EventListener + void event(Event::Channel channel, const Event &event) override; + + void applyQuestStatusEffects(Being *npc); + + private: + void updateQuestStatusEffects(); + + QuestEffectMap mActiveQuestEffects; }; } // namespace TmwAthena diff --git a/src/openglgraphics.cpp b/src/openglgraphics.cpp index ecd98ea1..667c91e8 100644 --- a/src/openglgraphics.cpp +++ b/src/openglgraphics.cpp @@ -91,8 +91,8 @@ OpenGLGraphics::OpenGLGraphics(SDL_Window *window, SDL_GLContext glContext) glGetIntegerv(GL_MAX_TEXTURE_SIZE, &texSize); } Image::mTextureSize = texSize; - logger->log("OpenGL texture size: %d pixels%s", Image::mTextureSize, - rectTex ? " (rectangle textures)" : ""); + Log::info("OpenGL texture size: %d pixels%s", Image::mTextureSize, + rectTex ? " (rectangle textures)" : ""); glMatrixMode(GL_TEXTURE); glLoadIdentity(); @@ -542,6 +542,7 @@ void OpenGLGraphics::drawRescaledImagePattern(const Image *image, void OpenGLGraphics::updateScreen() { SDL_GL_SwapWindow(mWindow); + SDL_ShowWindow(mWindow); /* * glFinish flushes all OpenGL commands and makes sure they have been diff --git a/src/particle.cpp b/src/particle.cpp index cb79c86f..5051672b 100644 --- a/src/particle.cpp +++ b/src/particle.cpp @@ -74,7 +74,7 @@ void Particle::setupEngine() Particle::fastPhysics = config.particleFastPhysics; Particle::emitterSkip = config.particleEmitterSkip + 1; Particle::enabled = config.particleEffects; - logger->log("Particle engine set up"); + Log::info("Particle engine set up"); } bool Particle::draw(Graphics *, int, int) const @@ -261,7 +261,7 @@ Particle *Particle::addEffect(const std::string &particleEffectFile, if (!rootNode || rootNode.name() != "effect") { - logger->log("Error loading particle: %s", particleEffectFile.c_str()); + Log::info("Error loading particle: %s", particleEffectFile.c_str()); return nullptr; } diff --git a/src/particleemitter.cpp b/src/particleemitter.cpp index 4954d317..e898b2fb 100644 --- a/src/particleemitter.cpp +++ b/src/particleemitter.cpp @@ -179,9 +179,8 @@ ParticleEmitter::ParticleEmitter(XML::Node emitterNode, Particle *target, } else { - logger->log("Particle Engine: Warning, unknown emitter property \"%s\"", - name.c_str() - ); + Log::info("Particle Engine: Warning, unknown emitter property \"%s\"", + name.c_str()); } } else if (propertyNode.name() == "emitter") diff --git a/src/playerinfo.cpp b/src/playerinfo.cpp index a05ffaaa..a96471a5 100644 --- a/src/playerinfo.cpp +++ b/src/playerinfo.cpp @@ -287,8 +287,8 @@ void clearAbilityStatus(int id) void setAbilityStatus(int id, int current, int max, int recharge) { - logger->log("AbilityUpdate Skill #%d -- (%d/%d) -> %d", id, current, max, - recharge); + Log::info("AbilityUpdate Skill #%d -- (%d/%d) -> %d", id, current, max, + recharge); mAbilities[id].currentMana = current; mAbilities[id].neededMana = max; mAbilities[id].recharge = recharge; diff --git a/src/resources/abilitydb.cpp b/src/resources/abilitydb.cpp index 311ee9eb..cb596ea8 100644 --- a/src/resources/abilitydb.cpp +++ b/src/resources/abilitydb.cpp @@ -41,7 +41,7 @@ static AbilityInfo::TargetMode targetModeFromString(const std::string& str) if (str == "direction") return AbilityInfo::TARGET_DIRECTION; - logger->log("AbilityDB: Warning, unknown target mode \"%s\"", str.c_str() ); + Log::info("AbilityDB: Warning, unknown target mode \"%s\"", str.c_str() ); return AbilityInfo::TARGET_BEING; } @@ -68,7 +68,7 @@ void AbilityDB::readAbilityNode(XML::Node node, const std::string &filename) info->rechargeCurrent = 0; if (mAbilityInfos.find(id) != mAbilityInfos.end()) - logger->log("AbilityDB: Duplicate ability ID %d in %s, ignoring", id, filename.c_str()); + Log::info("AbilityDB: Duplicate ability ID %d in %s, ignoring", id, filename.c_str()); else mAbilityInfos[id] = info; } diff --git a/src/resources/animation.cpp b/src/resources/animation.cpp index 91c22236..c529400f 100644 --- a/src/resources/animation.cpp +++ b/src/resources/animation.cpp @@ -84,7 +84,7 @@ Animation Animation::fromXML(XML::Node node, const std::string &dyePalettes) if (index < 0) { - logger->log("No valid value for 'index'"); + Log::info("No valid value for 'index'"); continue; } @@ -92,7 +92,7 @@ Animation Animation::fromXML(XML::Node node, const std::string &dyePalettes) if (!img) { - logger->log("No image at index %d", index); + Log::info("No image at index %d", index); continue; } @@ -105,7 +105,7 @@ Animation Animation::fromXML(XML::Node node, const std::string &dyePalettes) if (start < 0 || end < 0) { - logger->log("No valid value for 'start' or 'end'"); + Log::info("No valid value for 'start' or 'end'"); continue; } @@ -115,7 +115,7 @@ Animation Animation::fromXML(XML::Node node, const std::string &dyePalettes) if (!img) { - logger->log("No image at index %d", start); + Log::info("No image at index %d", start); continue; } diff --git a/src/resources/attributes.cpp b/src/resources/attributes.cpp index 7ec6b516..5b1018ee 100644 --- a/src/resources/attributes.cpp +++ b/src/resources/attributes.cpp @@ -240,22 +240,22 @@ namespace Attributes { int id = node.getProperty("id", 0); if (!id) { - logger->log("Attributes: Invalid or missing stat ID in " - DEFAULT_ATTRIBUTESDB_FILE "!"); + Log::info("Attributes: Invalid or missing stat ID in " + DEFAULT_ATTRIBUTESDB_FILE "!"); return; } if (attributes.find(id) != attributes.end()) { - logger->log("Attributes: Redefinition of stat ID %d", id); + Log::info("Attributes: Redefinition of stat ID %d", id); } std::string name = node.getProperty("name", ""); if (name.empty()) { - logger->log("Attributes: Invalid or missing stat name in " - DEFAULT_ATTRIBUTESDB_FILE "!"); + Log::info("Attributes: Invalid or missing stat name in " + DEFAULT_ATTRIBUTESDB_FILE "!"); return; } @@ -280,10 +280,10 @@ namespace Attributes { { if (name.empty()) { - logger->log("Attribute modifier in attribute %u:%s: " - "Empty name definition " - "on empty tag definition, skipping.", - a.id, a.name.c_str()); + Log::info("Attribute modifier in attribute %u:%s: " + "Empty name definition " + "on empty tag definition, skipping.", + a.id, a.name.c_str()); --count; continue; } @@ -296,10 +296,10 @@ namespace Attributes { { if (name.empty()) { - logger->log("Attribute modifier in attribute %u:%s: " - "Empty name definition " - "on empty effect definition, skipping.", - a.id, a.name.c_str()); + Log::info("Attribute modifier in attribute %u:%s: " + "Empty name definition " + "on empty effect definition, skipping.", + a.id, a.name.c_str()); --count; continue; } @@ -308,7 +308,7 @@ namespace Attributes { } tags.insert(std::make_pair(tag, effect)); } - logger->log("Found %d tags for attribute %d.", count, id); + Log::info("Found %d tags for attribute %d.", count, id); } /** @@ -321,8 +321,8 @@ namespace Attributes { DEFAULT_MIN_PTS); attributeMaximum = node.getProperty("maximum", DEFAULT_MAX_PTS); - logger->log("Loaded points: start: %i, min: %i, max: %i.", - creationPoints, attributeMinimum, attributeMaximum); + Log::info("Loaded points: start: %i, min: %i, max: %i.", + creationPoints, attributeMinimum, attributeMaximum); } /** @@ -330,8 +330,8 @@ namespace Attributes { */ void checkStatus() { - logger->log("Found %d tags for %d attributes.", int(tags.size()), - int(attributes.size())); + Log::info("Found %d tags for %d attributes.", int(tags.size()), + int(attributes.size())); if (attributes.size() == 0) { @@ -346,9 +346,9 @@ namespace Attributes { if (averageValue > attributeMaximum || averageValue < attributeMinimum || creationPoints < 1) { - logger->log("Attributes: Character's point values make " - "the character's creation impossible. " - "Switch back to defaults."); + Log::info("Attributes: Character's point values make " + "the character's creation impossible. " + "Switch back to defaults."); creationPoints = DEFAULT_POINTS; attributeMinimum = DEFAULT_MIN_PTS; attributeMaximum = DEFAULT_MAX_PTS; diff --git a/src/resources/beinginfo.cpp b/src/resources/beinginfo.cpp index 20c24d4f..f2edf1d8 100644 --- a/src/resources/beinginfo.cpp +++ b/src/resources/beinginfo.cpp @@ -73,8 +73,8 @@ void BeingInfo::setTargetCursorSize(const std::string &size) const auto cursorSize = targetCursorSizeFromString(size); if (!cursorSize) { - logger->log("Unknown targetCursor value \"%s\" for %s", - size.c_str(), name.c_str()); + Log::info("Unknown targetCursor value \"%s\" for %s", + size.c_str(), name.c_str()); } targetCursorSize = cursorSize.value_or(ActorSprite::TC_MEDIUM); } @@ -84,8 +84,8 @@ void BeingInfo::setHoverCursor(const std::string &cursorName) const auto cursor = cursorFromString(cursorName); if (!cursor) { - logger->log("Unknown hoverCursor value \"%s\" for %s", - cursorName.c_str(), name.c_str()); + Log::info("Unknown hoverCursor value \"%s\" for %s", + cursorName.c_str(), name.c_str()); } hoverCursor = cursor.value_or(Cursor::Pointer); } diff --git a/src/resources/chardb.cpp b/src/resources/chardb.cpp index 9001b6c2..97f86d3a 100644 --- a/src/resources/chardb.cpp +++ b/src/resources/chardb.cpp @@ -54,7 +54,7 @@ void CharDB::load() if (!root || root.name() != "chars") { - logger->log("CharDB: Failed to parse charcreation.xml."); + Log::info("CharDB: Failed to parse charcreation.xml."); return; } @@ -86,7 +86,7 @@ void CharDB::load() void CharDB::unload() { - logger->log("Unloading chars database..."); + Log::info("Unloading chars database..."); mLoaded = false; } diff --git a/src/resources/dye.cpp b/src/resources/dye.cpp index 0ecc9fd6..136c9334 100644 --- a/src/resources/dye.cpp +++ b/src/resources/dye.cpp @@ -63,8 +63,8 @@ DyePalette::DyePalette(const std::string &description) } else { - logger->log("Error, invalid embedded palette: %s", - description.c_str()); + Log::info("Error, invalid embedded palette: %s", + description.c_str()); return; } @@ -82,7 +82,7 @@ DyePalette::DyePalette(const std::string &description) ++pos; } - logger->log("Error, invalid embedded palette: %s", description.c_str()); + Log::info("Error, invalid embedded palette: %s", description.c_str()); } void DyePalette::getColor(int intensity, int color[3]) const @@ -195,7 +195,7 @@ Dye::Dye(const std::string &description) if (next_pos <= pos + 3 || description[pos + 1] != ':') { - logger->log("Error, invalid dye: %s", description.c_str()); + Log::info("Error, invalid dye: %s", description.c_str()); return; } @@ -211,7 +211,7 @@ Dye::Dye(const std::string &description) case 'C': i = 5; break; case 'W': i = 6; break; default: - logger->log("Error, invalid dye: %s", description.c_str()); + Log::info("Error, invalid dye: %s", description.c_str()); return; } mDyePalettes[i] = new DyePalette(description.substr(pos + 2, @@ -289,7 +289,7 @@ void Dye::instantiate(std::string &target, const std::string &palettes) } else { - logger->log("Error, invalid dye placeholder: %s", target.c_str()); + Log::info("Error, invalid dye placeholder: %s", target.c_str()); return; } s << target[next_pos]; diff --git a/src/resources/dye.h b/src/resources/dye.h index 0fe68f07..1730d2fd 100644 --- a/src/resources/dye.h +++ b/src/resources/dye.h @@ -35,7 +35,7 @@ class DyePalette * The string is either a file name or a sequence of hexadecimal RGB * values separated by ',' and starting with '#'. */ - DyePalette(const std::string &pallete); + DyePalette(const std::string &description); /** * Gets a pixel color depending on its intensity. First color is diff --git a/src/resources/emotedb.cpp b/src/resources/emotedb.cpp index d29483d1..c0f5f777 100644 --- a/src/resources/emotedb.cpp +++ b/src/resources/emotedb.cpp @@ -51,7 +51,7 @@ void EmoteDB::readEmoteNode(XML::Node node, const std::string &filename) const int id = node.getProperty("id", -1); if (id == -1) { - logger->log("Emote Database: Emote with missing ID in %s!", filename.c_str()); + Log::info("Emote Database: Emote with missing ID in %s!", filename.c_str()); return; } @@ -63,8 +63,8 @@ void EmoteDB::readEmoteNode(XML::Node node, const std::string &filename) if (emote.effectId == -1) { - logger->log("Emote Database: Warning: Emote %s has no attached effect in %s!", - emote.name.c_str(), filename.c_str()); + Log::info("Emote Database: Warning: Emote %s has no attached effect in %s!", + emote.name.c_str(), filename.c_str()); return; } @@ -74,8 +74,8 @@ void EmoteDB::readEmoteNode(XML::Node node, const std::string &filename) if (imageName.empty() || width <= 0 || height <= 0) { - logger->log("Emote Database: Warning: Emote %s has bad imageset values in %s", - emote.name.c_str(), filename.c_str()); + Log::info("Emote Database: Warning: Emote %s has bad imageset values in %s", + emote.name.c_str(), filename.c_str()); return; } @@ -85,8 +85,8 @@ void EmoteDB::readEmoteNode(XML::Node node, const std::string &filename) if (!emote.is || emote.is->size() == 0) { - logger->log("Emote Database: Error loading imageset for emote %s in %s", - emote.name.c_str(), filename.c_str()); + Log::info("Emote Database: Error loading imageset for emote %s in %s", + emote.name.c_str(), filename.c_str()); return; } @@ -119,7 +119,7 @@ const Emote &EmoteDB::get(int id) if (i == mEmotes.end()) { - logger->log("EmoteDB: Warning, unknown emote ID %d requested", id); + Log::info("EmoteDB: Warning, unknown emote ID %d requested", id); return mUnknown; } diff --git a/src/resources/hairdb.cpp b/src/resources/hairdb.cpp index 6b88a4df..312188d6 100644 --- a/src/resources/hairdb.cpp +++ b/src/resources/hairdb.cpp @@ -40,7 +40,7 @@ void HairDB::readHairColorNode(XML::Node node, const std::string &filename) int id = node.getProperty("id", 0); if (mHairColors.find(id) != mHairColors.end()) - logger->log("HairDb: Redefinition of color Id %d in %s", id, filename.c_str()); + Log::info("HairDb: Redefinition of color Id %d in %s", id, filename.c_str()); mHairColors[id] = node.getProperty("value", COLOR_WHITE); } @@ -55,7 +55,7 @@ void HairDB::unload() if (!mLoaded) return; - logger->log("Unloading hair style and color database..."); + Log::info("Unloading hair style and color database..."); mHairColors.clear(); mHairStyles.clear(); @@ -71,7 +71,7 @@ void HairDB::addHairStyle(int id) id = -id; if (mHairStyles.find(id) != mHairStyles.end()) - logger->log("Warning: Redefinition of hairstyle id %i:", id); + Log::warn("Redefinition of hairstyle id %i:", id); mHairStyles.insert(id); } @@ -81,13 +81,13 @@ const std::string &HairDB::getHairColor(int id) const if (!mLoaded) { // no idea if this can happen, but that check existed before - logger->log("WARNING: HairDB::getHairColor() called before settings were loaded!"); + Log::warn("HairDB::getHairColor() called before settings were loaded!"); } auto it = mHairColors.find(id); if (it != mHairColors.end()) return it->second; - logger->log("HairDb: Error, unknown color Id# %d", id); + Log::info("HairDb: Error, unknown color Id# %d", id); return mHairColors.at(0); } diff --git a/src/resources/image.cpp b/src/resources/image.cpp index b36aea01..11d5c275 100644 --- a/src/resources/image.cpp +++ b/src/resources/image.cpp @@ -54,8 +54,7 @@ Image::Image(SDL_Texture *texture, int width, int height): if (!texture) { - logger->log( - "Image::Image(SDL_Texture*, ...): Couldn't load invalid Surface!"); + Log::info("Image::Image(SDL_Texture*, ...): Couldn't load invalid Surface!"); } } @@ -72,8 +71,7 @@ Image::Image(GLuint glimage, int width, int height, int texWidth, int texHeight) if (glimage == 0) { - logger->log( - "Image::Image(GLuint, ...): Couldn't load invalid Surface!"); + Log::info("Image::Image(GLuint, ...): Couldn't load invalid Surface!"); } } #endif @@ -101,7 +99,7 @@ Resource *Image::load(SDL_RWops *rw) if (!tmpImage) { - logger->log("Error, image load failed: %s", IMG_GetError()); + Log::info("Error, image load failed: %s", IMG_GetError()); return nullptr; } @@ -117,20 +115,20 @@ Resource *Image::load(SDL_RWops *rw, const Dye &dye) if (!surf) { - logger->log("Error, image load failed: %s", IMG_GetError()); + Log::info("Error, image load failed: %s", IMG_GetError()); return nullptr; } if (surf->format->format != SDL_PIXELFORMAT_RGBA32) { - logger->log("Warning: image format is %s, not SDL_PIXELFORMAT_RGBA32. Converting...", - SDL_GetPixelFormatName(surf->format->format)); + Log::warn("Image format is %s, not SDL_PIXELFORMAT_RGBA32. Converting...", + SDL_GetPixelFormatName(surf->format->format)); SDL_Surface *convertedSurf = SDL_ConvertSurfaceFormat(surf, SDL_PIXELFORMAT_RGBA32, 0); SDL_FreeSurface(surf); if (!convertedSurf) { - logger->log("Error, image convert failed: %s", SDL_GetError()); + Log::info("Error, image convert failed: %s", SDL_GetError()); return nullptr; } surf = convertedSurf; @@ -219,8 +217,8 @@ Image *Image::_GLload(SDL_Surface *image) if (realWidth < width || realHeight < height) { - logger->log("Warning: image too large, cropping to %dx%d texture!", - realWidth, realHeight); + Log::warn("Image too large, cropping to %dx%d texture!", + realWidth, realHeight); } // Determine 32-bit masks based on byte order @@ -253,7 +251,7 @@ Image *Image::_GLload(SDL_Surface *image) if (!image) { - logger->log("Error, image convert failed: out of memory"); + Log::info("Error, image convert failed: out of memory"); return nullptr; } @@ -308,7 +306,7 @@ Image *Image::_GLload(SDL_Surface *image) errmsg = "GL_OUT_OF_MEMORY"; break; } - logger->log("Error: Image GL import failed: %s", errmsg); + Log::error("Image GL import failed: %s", errmsg); return nullptr; } diff --git a/src/resources/imageset.cpp b/src/resources/imageset.cpp index 34cf1fd8..1f194b4f 100644 --- a/src/resources/imageset.cpp +++ b/src/resources/imageset.cpp @@ -50,7 +50,7 @@ Image *ImageSet::get(size_t i) const { if (i >= mImages.size()) { - logger->log("Warning: No sprite %d in this image set", (int) i); + Log::warn("No sprite %d in this image set", (int) i); return nullptr; } diff --git a/src/resources/imagewriter.cpp b/src/resources/imagewriter.cpp index ddf1fbee..cf4c6803 100644 --- a/src/resources/imagewriter.cpp +++ b/src/resources/imagewriter.cpp @@ -42,7 +42,7 @@ bool ImageWriter::writePNG(SDL_Surface *surface, const std::string &filename) png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); if (!png_ptr) { - logger->log("Had trouble creating png_structp"); + Log::info("Had trouble creating png_structp"); return false; } @@ -50,21 +50,21 @@ bool ImageWriter::writePNG(SDL_Surface *surface, const std::string &filename) if (!info_ptr) { png_destroy_write_struct(&png_ptr, (png_infopp)nullptr); - logger->log("Could not create png_info"); + Log::info("Could not create png_info"); return false; } if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_write_struct(&png_ptr, (png_infopp)nullptr); - logger->log("problem writing to %s", filename.c_str()); + Log::info("problem writing to %s", filename.c_str()); return false; } FILE *fp = fopen(filename.c_str(), "wb"); if (!fp) { - logger->log("could not open file %s for writing", filename.c_str()); + Log::info("could not open file %s for writing", filename.c_str()); return false; } @@ -83,7 +83,7 @@ bool ImageWriter::writePNG(SDL_Surface *surface, const std::string &filename) row_pointers = new png_bytep[surface->h]; if (!row_pointers) { - logger->log("Had trouble converting surface to row pointers"); + Log::info("Had trouble converting surface to row pointers"); fclose(fp); return false; } diff --git a/src/resources/itemdb.cpp b/src/resources/itemdb.cpp index 05f6ad0b..1d217fc2 100644 --- a/src/resources/itemdb.cpp +++ b/src/resources/itemdb.cpp @@ -148,7 +148,7 @@ const ItemInfo &ItemDB::get(int id) const auto i = mItemInfos.find(id); if (i == mItemInfos.end()) { - logger->log("ItemDB: Warning, unknown item ID# %d", id); + Log::info("ItemDB: Warning, unknown item ID# %d", id); return *mUnknown; } @@ -164,8 +164,8 @@ const ItemInfo &ItemDB::get(const std::string &name) const { if (!name.empty()) { - logger->log("ItemDB: Warning, unknown item name \"%s\"", - name.c_str()); + Log::info("ItemDB: Warning, unknown item name \"%s\"", + name.c_str()); } return *mUnknown; } @@ -202,8 +202,8 @@ void ItemDB::loadSoundRef(ItemInfo &itemInfo, XML::Node node) } else { - logger->log("ItemDB: Ignoring unknown sound event '%s'", - event.c_str()); + Log::info("ItemDB: Ignoring unknown sound event '%s'", + event.c_str()); } } @@ -237,15 +237,15 @@ void ItemDB::loadReplacement(ItemInfo &info, XML::Node replaceNode) if (sprite == SPRITE_UNKNOWN) { - logger->log("ItemDB: Invalid sprite name '%s' in replace tag", - spriteString.data()); + Log::info("ItemDB: Invalid sprite name '%s' in replace tag", + spriteString.data()); return; } if (direction == DIRECTION_UNKNOWN) { - logger->log("ItemDB: Invalid direction name '%s' in replace tag", - directionString.data()); + Log::info("ItemDB: Invalid direction name '%s' in replace tag", + directionString.data()); return; } @@ -266,7 +266,7 @@ void ItemDB::loadReplacement(ItemInfo &info, XML::Node replaceNode) void ItemDB::unload() { - logger->log("Unloading item database..."); + Log::info("Unloading item database..."); delete mUnknown; mUnknown = nullptr; @@ -283,12 +283,12 @@ void ItemDB::loadCommonRef(ItemInfo &itemInfo, XML::Node node, const std::string if (!itemInfo.id) { - logger->log("ItemDB: Invalid or missing item Id in %s!", filename.c_str()); + Log::info("ItemDB: Invalid or missing item Id in %s!", filename.c_str()); return; } else if (mItemInfos.find(itemInfo.id) != mItemInfos.end()) { - logger->log("ItemDB: Redefinition of item Id %d in %s", itemInfo.id, filename.c_str()); + Log::info("ItemDB: Redefinition of item Id %d in %s", itemInfo.id, filename.c_str()); } itemInfo.mView = node.getProperty("view", 0); @@ -346,8 +346,8 @@ void ItemDB::addItem(ItemInfo *itemInfo) if (itr == mNamedItemInfos.end()) mNamedItemInfos[temp] = itemInfo; else - logger->log("ItemDB: Duplicate name (%s) for item id %d found.", - temp.c_str(), itemInfo->id); + Log::info("ItemDB: Duplicate name (%s) for item id %d found.", + temp.c_str(), itemInfo->id); } } @@ -359,7 +359,7 @@ static void checkParameter(int id, const T param, const T errorValue) std::stringstream errMsg; errMsg << "ItemDB: Missing " << param << " attribute for item id " << id << "!"; - logger->log("%s", errMsg.str().c_str()); + Log::info("%s", errMsg.str().c_str()); } } @@ -368,7 +368,7 @@ void ItemDB::checkItemInfo(ItemInfo &itemInfo) int id = itemInfo.id; if (!itemInfo.attackAction.empty()) if (itemInfo.attackRange == 0) - logger->log("ItemDB: Missing attack range from weapon %i!", id); + Log::info("ItemDB: Missing attack range from weapon %i!", id); if (id >= 0) { @@ -504,7 +504,7 @@ void ManaServItemDB::readItemNode(XML::Node node, const std::string &filename) std::string trigger = itemChild.getProperty("trigger", std::string()); if (trigger.empty()) { - logger->log("Found empty trigger effect label in %s, skipping.", filename.c_str()); + Log::info("Found empty trigger effect label in %s, skipping.", filename.c_str()); continue; } @@ -514,8 +514,8 @@ void ManaServItemDB::readItemNode(XML::Node node, const std::string &filename) auto triggerLabel = triggerTable.find(trigger); if (triggerLabel == triggerTable.end()) { - logger->log("Warning: unknown trigger %s in item %d!", - trigger.c_str(), itemInfo->id); + Log::warn("Unknown trigger %s in item %d!", + trigger.c_str(), itemInfo->id); continue; } @@ -528,7 +528,7 @@ void ManaServItemDB::readItemNode(XML::Node node, const std::string &filename) int duration = effectChild.getProperty("duration", 0); if (attribute.empty() || !value) { - logger->log("Warning: incomplete modifier definition in %s, skipping.", filename.c_str()); + Log::warn("Incomplete modifier definition in %s, skipping.", filename.c_str()); continue; } auto it = extraStats.cbegin(); @@ -537,7 +537,7 @@ void ManaServItemDB::readItemNode(XML::Node node, const std::string &filename) ++it; if (it == extraStats.end()) { - logger->log("Warning: unknown modifier tag %s in %s, skipping.", attribute.c_str(), filename.c_str()); + Log::warn("Unknown modifier tag %s in %s, skipping.", attribute.c_str(), filename.c_str()); continue; } effect.push_back( diff --git a/src/resources/mapreader.cpp b/src/resources/mapreader.cpp index b952cdcc..3ca5763c 100644 --- a/src/resources/mapreader.cpp +++ b/src/resources/mapreader.cpp @@ -77,7 +77,7 @@ static std::string resolveRelativePath(std::string base, std::string relative) Map *MapReader::readMap(const std::string &filename) { - logger->log("Attempting to read map %s", filename.c_str()); + Log::info("Attempting to read map %s", filename.c_str()); Map *map = nullptr; XML::Document doc(filename); @@ -89,7 +89,7 @@ Map *MapReader::readMap(const std::string &filename) { if (node.name() != "map") { - logger->log("Error: Not a map file (%s)!", filename.c_str()); + Log::error("Not a map file (%s)!", filename.c_str()); } else { @@ -98,7 +98,7 @@ Map *MapReader::readMap(const std::string &filename) } else { - logger->log("Error while parsing map file (%s)!", filename.c_str()); + Log::info("Error while parsing map file (%s)!", filename.c_str()); } if (map) @@ -119,9 +119,9 @@ Map *MapReader::readMap(XML::Node node, const std::string &path) if (tilew < 0 || tileh < 0) { - logger->log("MapReader: Warning: " - "Unitialized tile width or height value for map: %s", - path.c_str()); + Log::info("MapReader: Warning: " + "Unitialized tile width or height value for map: %s", + path.c_str()); return nullptr; } @@ -174,15 +174,15 @@ Map *MapReader::readMap(XML::Node node, const std::string &path) const int objW = objectNode.getProperty("width", 0); const int objH = objectNode.getProperty("height", 0); - logger->log("- Loading object name: %s type: %s at %d:%d", - objName.c_str(), objType.c_str(), - objX, objY); + Log::info("- Loading object name: %s type: %s at %d:%d", + objName.c_str(), objType.c_str(), + objX, objY); if (objType == "PARTICLE_EFFECT") { if (objName.empty()) { - logger->log(" Warning: No particle file given"); + Log::info(" Warning: No particle file given"); continue; } @@ -203,7 +203,7 @@ Map *MapReader::readMap(XML::Node node, const std::string &path) } else { - logger->log(" Warning: Unknown object type"); + Log::info(" Warning: Unknown object type"); } } } @@ -293,7 +293,7 @@ static void readLayer(XML::Node node, Map *map) map->addLayer(layer); } - logger->log("- Loading layer \"%s\"", name.c_str()); + Log::info("- Loading layer \"%s\"", name.c_str()); int x = 0; int y = 0; @@ -333,8 +333,8 @@ static void readLayer(XML::Node node, Map *map) if (!compression.empty() && compression != "gzip" && compression != "zlib") { - logger->log("Warning: only gzip or zlib layer " - "compression supported!"); + Log::warn("Only gzip or zlib layer " + "compression supported!"); return; } @@ -383,7 +383,7 @@ static void readLayer(XML::Node node, Map *map) if (!inflated) { - logger->log("Error: Could not decompress layer!"); + Log::error("Could not decompress layer!"); return; } } @@ -415,7 +415,7 @@ static void readLayer(XML::Node node, Map *map) const auto data = childNode.textContent(); if (data.empty()) { - logger->log("Error: CSV layer data is empty!"); + Log::error("CSV layer data is empty!"); continue; } @@ -432,7 +432,7 @@ static void readLayer(XML::Node node, Map *map) if (errno == ERANGE) { - logger->log("Error: Range error in tile layer data!"); + Log::error("Range error in tile layer data!"); break; } @@ -452,7 +452,7 @@ static void readLayer(XML::Node node, Map *map) pos = strchr(end, ','); if (!pos) { - logger->log("Error: CSV layer data too short!"); + Log::error("CSV layer data too short!"); break; } ++pos; @@ -536,8 +536,7 @@ static Tileset *readTileset(XML::Node node, const std::string &path, } else { - logger->log("Warning: Failed to load tileset (%s)", - source.c_str()); + Log::warn("Failed to load tileset (%s)", source.c_str()); } } } diff --git a/src/resources/monsterdb.cpp b/src/resources/monsterdb.cpp index 4963f93f..7f092a0e 100644 --- a/src/resources/monsterdb.cpp +++ b/src/resources/monsterdb.cpp @@ -111,11 +111,11 @@ void MonsterDB::readMonsterNode(XML::Node node, const std::string &filename) } else { - logger->log("MonsterDB: Warning, sound effect %s for " - "unknown event %s of monster %s in %s", - soundFile.c_str(), event.c_str(), - currentInfo->name.c_str(), - filename.c_str()); + Log::info("MonsterDB: Warning, sound effect %s for " + "unknown event %s of monster %s in %s", + soundFile.c_str(), event.c_str(), + currentInfo->name.c_str(), + filename.c_str()); } } else if (spriteNode.name() == "attack") @@ -168,7 +168,7 @@ BeingInfo *MonsterDB::get(int id) if (i == mMonsterInfos.end()) { - logger->log("MonsterDB: Warning, unknown monster ID %d requested", id); + Log::info("MonsterDB: Warning, unknown monster ID %d requested", id); return BeingInfo::Unknown; } diff --git a/src/resources/music.cpp b/src/resources/music.cpp index 069af588..b73d89ce 100644 --- a/src/resources/music.cpp +++ b/src/resources/music.cpp @@ -40,7 +40,7 @@ Music *Music::load(SDL_RWops *rw) return new Music(music); } - logger->log("Error, failed to load music: %s", Mix_GetError()); + Log::info("Error, failed to load music: %s", Mix_GetError()); return nullptr; } diff --git a/src/resources/npcdb.cpp b/src/resources/npcdb.cpp index 6b1c3150..44292525 100644 --- a/src/resources/npcdb.cpp +++ b/src/resources/npcdb.cpp @@ -46,7 +46,7 @@ void NPCDB::readNPCNode(XML::Node node, const std::string &filename) int id = node.getProperty("id", 0); if (id == 0) { - logger->log("NPC Database: NPC with missing ID in %s", filename.c_str()); + Log::info("NPC Database: NPC with missing ID in %s", filename.c_str()); return; } @@ -94,7 +94,7 @@ BeingInfo *NPCDB::get(int id) if (i == mNPCInfos.end()) { - logger->log("NPCDB: Warning, unknown NPC ID %d requested", id); + Log::info("NPCDB: Warning, unknown NPC ID %d requested", id); return BeingInfo::Unknown; } diff --git a/src/resources/questdb.cpp b/src/resources/questdb.cpp new file mode 100644 index 00000000..1424c20e --- /dev/null +++ b/src/resources/questdb.cpp @@ -0,0 +1,232 @@ +/* + * The Mana Client + * Copyright (C) 2025 The Mana Developers + * + * This file is part of The Mana Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "resources/questdb.h" +#include "log.h" + +#include <algorithm> +#include <unordered_map> +#include <utility> + +namespace QuestDB { + +// The quests are stored in a map using their variable ID as the key +static std::unordered_map<int, Quest> quests; + +// Helper function to check if a container contains a value +template<typename Container, typename Value> +static bool contains(const Container &container, const Value &value) +{ + return std::find(container.begin(), container.end(), value) != container.end(); +} + +void init() +{ + unload(); +} + +void readQuestVarNode(XML::Node node, const std::string &filename) +{ + int varId = 0; + if (!node.attribute("id", varId)) + return; + + Quest &quest = quests[varId]; + + for (auto child : node.children()) + { + if (child.name() == "effect") + { + QuestEffect &effect = quest.effects.emplace_back(); + child.attribute("map", effect.map); + child.attribute("npc", effect.npcId); + child.attribute("effect", effect.statusEffectId); + child.attribute("value", effect.values); + + if (effect.map.empty() || effect.npcId == 0 || effect.statusEffectId == 0 || effect.values.empty()) + { + Log::warn("effect node for var %d is missing required attributes", varId); + } + } + else if (child.name() == "quest") + { + QuestState &state = quest.states.emplace_back(); + child.attribute("name", state.name); + child.attribute("group", state.group); + child.attribute("incomplete", state.incomplete); + child.attribute("complete", state.complete); + + if (state.incomplete.empty() && state.complete.empty()) + { + Log::warn("quest node for var %d ('%s') has neither 'complete' nor 'incomplete' values", + varId, state.name.c_str()); + continue; + } + + for (auto questChild : child.children()) + { + QuestRowType rowType; + std::string_view tag = questChild.name(); + if (tag == "text") + rowType = QuestRowType::Text; + else if (tag == "name") + rowType = QuestRowType::Name; + else if (tag == "reward") + rowType = QuestRowType::Reward; + else if (tag == "questgiver" || tag == "giver") + rowType = QuestRowType::Giver; + else if (tag == "coordinates") + rowType = QuestRowType::Coordinates; + else if (tag == "npc") + rowType = QuestRowType::NPC; + else + { + Log::warn("unknown quest row type '%s' for var %d ('%s')", + tag.data(), varId, state.name.c_str()); + continue; + } + + QuestRow &row = state.rows.emplace_back(rowType); + row.text = questChild.textContent(); + + if (rowType == QuestRowType::Coordinates) + { + questChild.attribute("x", row.x); + questChild.attribute("y", row.y); + } + } + } + } +} + +void unload() +{ + quests.clear(); +} + +bool hasQuests() +{ + return !quests.empty(); +} + +// In quests, the map name may include the file extension. This is discouraged +// but supported for compatibility. +static std::string_view baseName(const std::string &fileName) +{ + auto pos = fileName.find_last_of('.'); + return pos == std::string::npos ? fileName : std::string_view(fileName.data(), pos); +} + +QuestEffectMap getActiveEffects(const QuestVars &questVars, + const std::string &mapName) +{ + QuestEffectMap activeEffects; + + for (auto &[var, quest] : std::as_const(quests)) + { + auto value = questVars.get(var); + + for (auto &effect : quest.effects) + { + if (baseName(effect.map) != mapName) + continue; + if (!contains(effect.values, value)) + continue; + + activeEffects.set(effect.npcId, effect.statusEffectId); + } + } + + return activeEffects; +} + +std::vector<QuestEntry> getQuestsEntries(const QuestVars &questVars, + bool skipCompleted) +{ + std::vector<QuestEntry> activeQuests; + + for (auto &[varId, quest] : std::as_const(quests)) + { + auto value = questVars.get(varId); + + for (auto &state : quest.states) + { + bool matchesIncomplete = contains(state.incomplete, value); + bool matchesComplete = contains(state.complete, value); + + if (skipCompleted && matchesComplete) + continue; + + if (matchesIncomplete || matchesComplete) + { + QuestEntry &entry = activeQuests.emplace_back(); + entry.varId = varId; + entry.completed = matchesComplete; + entry.state = &state; + } + } + } + + return activeQuests; +} + +static std::pair<int, int> countQuestEntries(const Quest &quest, int value) +{ + int totalEntries = 0; + int completedEntries = 0; + + for (const auto &state : quest.states) + { + bool matchesIncomplete = contains(state.incomplete, value); + bool matchesComplete = contains(state.complete, value); + + if (matchesIncomplete || matchesComplete) + { + totalEntries++; + if (matchesComplete) + completedEntries++; + } + } + + return { totalEntries, completedEntries }; +} + +QuestChange questChange(int varId, int oldValue, int newValue) +{ + if (newValue == oldValue) + return QuestChange::None; + + auto questIt = quests.find(varId); + if (questIt == quests.end()) + return QuestChange::None; + + const Quest &quest = questIt->second; + + auto [oldQuestEntries, oldCompletedEntries] = countQuestEntries(quest, oldValue); + auto [newQuestEntries, newCompletedEntries] = countQuestEntries(quest, newValue); + + if (newCompletedEntries > oldCompletedEntries) + return QuestChange::Completed; + if (newQuestEntries > oldQuestEntries) + return QuestChange::New; + return QuestChange::None; +} + +} // namespace QuestDB diff --git a/src/resources/questdb.h b/src/resources/questdb.h new file mode 100644 index 00000000..43996b0b --- /dev/null +++ b/src/resources/questdb.h @@ -0,0 +1,139 @@ +/* + * The Mana Client + * Copyright (C) 2025 The Mana Developers + * + * This file is part of The Mana Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once + +#include "utils/xml.h" + +#include <map> +#include <string> +#include <vector> + +/** + * A map that returns a default value for non-existent keys. + */ +template<typename Key, typename Value, Value def = Value()> +class MapWithDefault +{ +public: + void set(Key key, Value value) + { + mVars[key] = value; + } + + Value get(Key key) const + { + auto it = mVars.find(key); + return it != mVars.end() ? it->second : def; + } + + void clear() + { + mVars.clear(); + } + +private: + std::map<Key, Value> mVars; +}; + +struct QuestEffect +{ + std::vector<int> values; // Quest variable values to which the effect applies + std::string map; // Map name the NPC is located on + int npcId = 0; + int statusEffectId = 0; +}; + +// Map of quest variables, from variable ID to value +using QuestVars = MapWithDefault<int, int>; + +// Map of quest effects, from NPC ID to status effect ID +using QuestEffectMap = MapWithDefault<int, int>; + +enum class QuestRowType +{ + Text, + Name, + Reward, + Giver, + Coordinates, + NPC +}; + +struct QuestRow +{ + QuestRow(QuestRowType type) + : type(type) + {} + + QuestRowType type; + std::string text; + int x = 0; + int y = 0; +}; + +struct QuestState +{ + std::string name; // Name of the quest in this state + std::string group; // Group name of the quest in this state + std::vector<int> incomplete; // Quest variable values for this state (quest incomplete) + std::vector<int> complete; // Quest variable values for this state (quest complete) + std::vector<QuestRow> rows; // Rows of text in the Quests window for this state +}; + +struct Quest +{ + std::vector<QuestEffect> effects; + std::vector<QuestState> states; +}; + +struct QuestEntry +{ + int varId; + bool completed; + const QuestState *state; + + const std::string &name() const { return state->name; } + const std::vector<QuestRow> &rows() const { return state->rows; } +}; + +enum class QuestChange +{ + None, + New, + Completed +}; + +namespace QuestDB +{ + void init(); + void readQuestVarNode(XML::Node node, const std::string &filename); + void unload(); + + bool hasQuests(); + + QuestEffectMap getActiveEffects(const QuestVars &questVars, + const std::string &mapName); + + std::vector<QuestEntry> getQuestsEntries(const QuestVars &questVars, + bool skipCompleted = false); + + QuestChange questChange(int varId, int oldValue, int newValue); +}; diff --git a/src/resources/resource.cpp b/src/resources/resource.cpp index cdff8060..17864cf5 100644 --- a/src/resources/resource.cpp +++ b/src/resources/resource.cpp @@ -31,7 +31,7 @@ void Resource::decRef(OrphanPolicy orphanPolicy) { // Reference may not already have reached zero if (mRefCount == 0) { - logger->log("Warning: mRefCount already zero for %s", mIdPath.c_str()); + Log::warn("mRefCount already zero for %s", mIdPath.c_str()); assert(false); } diff --git a/src/resources/resourcemanager.cpp b/src/resources/resourcemanager.cpp index e62407e3..2857c0df 100644 --- a/src/resources/resourcemanager.cpp +++ b/src/resources/resourcemanager.cpp @@ -45,7 +45,7 @@ ResourceManager *ResourceManager::instance = nullptr; ResourceManager::ResourceManager() { - logger->log("Initializing resource manager..."); + Log::info("Initializing resource manager..."); } ResourceManager::~ResourceManager() @@ -86,11 +86,11 @@ void ResourceManager::cleanUp(Resource *res) { if (res->mRefCount > 0) { - logger->log("ResourceManager::~ResourceManager() cleaning up %d " - "reference%s to %s", - res->mRefCount, - (res->mRefCount == 1) ? "" : "s", - res->mIdPath.c_str()); + Log::info("ResourceManager::~ResourceManager() cleaning up %d " + "reference%s to %s", + res->mRefCount, + (res->mRefCount == 1) ? "" : "s", + res->mIdPath.c_str()); } delete res; @@ -118,7 +118,7 @@ void ResourceManager::cleanOrphans() } else { - logger->log("ResourceManager::release(%s)", res->mIdPath.c_str()); + Log::info("ResourceManager::release(%s)", res->mIdPath.c_str()); iter = mOrphanedResources.erase(iter); delete res; // delete only after removal from list, to avoid issues in recursion } @@ -129,12 +129,12 @@ void ResourceManager::cleanOrphans() bool ResourceManager::addToSearchPath(const std::string &path, bool append) { - logger->log("Adding to PhysicsFS: %s", path.c_str()); if (!FS::addToSearchPath(path, append)) { - logger->log("Error: %s", FS::getLastError()); + Log::error("Couldn't add search path: %s (%s)", path.c_str(), FS::getLastError()); return false; } + Log::info("Added search path: %s", path.c_str()); return true; } diff --git a/src/resources/settingsmanager.cpp b/src/resources/settingsmanager.cpp index 9323d4d1..3dfb5eb4 100644 --- a/src/resources/settingsmanager.cpp +++ b/src/resources/settingsmanager.cpp @@ -27,6 +27,7 @@ #include "resources/monsterdb.h" #include "resources/npcdb.h" #include "resources/abilitydb.h" +#include "resources/questdb.h" #include "resources/statuseffectdb.h" #include "net/net.h" @@ -38,6 +39,9 @@ #include "log.h" #include "units.h" +#include <string> +#include <set> + namespace SettingsManager { static std::string mSettingsFile; @@ -53,6 +57,7 @@ namespace SettingsManager hairDB.init(); itemDb->init(); MonsterDB::init(); + QuestDB::init(); AbilityDB::init(); NPCDB::init(); EmoteDB::init(); @@ -96,6 +101,7 @@ namespace SettingsManager NPCDB::unload(); AbilityDB::unload(); MonsterDB::unload(); + QuestDB::unload(); if (itemDb) itemDb->unload(); hairDB.unload(); @@ -107,7 +113,7 @@ namespace SettingsManager */ static bool loadFile(const std::string &filename) { - logger->log("Loading game settings from %s", filename.c_str()); + Log::info("Loading game settings from %s", filename.c_str()); XML::Document doc(filename); XML::Node node = doc.rootNode(); @@ -118,7 +124,7 @@ namespace SettingsManager // FIXME: check root node's name when bjorn decides it's time if (!node /*|| node.name() != "settings" */) { - logger->log("Settings Manager: %s is not a valid settings file!", filename.c_str()); + Log::info("Settings Manager: %s is not a valid settings file!", filename.c_str()); return false; } @@ -156,7 +162,7 @@ namespace SettingsManager // check if we're not entering a loop if (mIncludedFiles.find(includeFile) != mIncludedFiles.end()) { - logger->log("Warning: Circular include loop detecting while including %s from %s", includeFile.c_str(), filename.c_str()); + Log::warn("Circular include loop detecting while including %s from %s", includeFile.c_str(), filename.c_str()); } else { @@ -165,7 +171,7 @@ namespace SettingsManager } else { - logger->log("Warning: <include> element without 'file' or 'name' attribute in %s", filename.c_str()); + Log::warn("<include> element without 'file' or 'name' attribute in %s", filename.c_str()); } } else if (childNode.name() == "option") @@ -177,7 +183,7 @@ namespace SettingsManager if (!name.empty()) paths.setValue(name, value); else - logger->log("Warning: option without a name found in %s", filename.c_str()); + Log::warn("option without a name found in %s", filename.c_str()); } else if (childNode.name() == "attribute") { @@ -221,6 +227,10 @@ namespace SettingsManager { NPCDB::readNPCNode(childNode, filename); } + else if (childNode.name() == "var") + { + QuestDB::readQuestVarNode(childNode, filename); + } else if (childNode.name() == "emote") { EmoteDB::readEmoteNode(childNode, filename); diff --git a/src/resources/settingsmanager.h b/src/resources/settingsmanager.h index 5b70f865..d9a6994c 100644 --- a/src/resources/settingsmanager.h +++ b/src/resources/settingsmanager.h @@ -20,10 +20,6 @@ #pragma once -#include <string> -#include <list> -#include <set> - namespace SettingsManager { void load(); diff --git a/src/resources/soundeffect.cpp b/src/resources/soundeffect.cpp index 19d7a820..1b0492d7 100644 --- a/src/resources/soundeffect.cpp +++ b/src/resources/soundeffect.cpp @@ -36,7 +36,7 @@ SoundEffect *SoundEffect::load(SDL_RWops *rw) return new SoundEffect(soundEffect); } - logger->log("Error, failed to load sound effect: %s", Mix_GetError()); + Log::info("Error, failed to load sound effect: %s", Mix_GetError()); return nullptr; } diff --git a/src/resources/spritedef.cpp b/src/resources/spritedef.cpp index 85e5e566..0e7f12dd 100644 --- a/src/resources/spritedef.cpp +++ b/src/resources/spritedef.cpp @@ -44,7 +44,7 @@ Action *SpriteDef::getAction(const std::string &action) const if (i == mActions.end()) { - logger->log("Warning: no action \"%s\" defined!", action.c_str()); + Log::warn("No action \"%s\" defined!", action.c_str()); return nullptr; } @@ -66,7 +66,7 @@ SpriteDef *SpriteDef::load(const std::string &animationFile, int variant) if (!rootNode || rootNode.name() != "sprite") { - logger->log("Error, failed to parse %s", animationFile.c_str()); + Log::info("Error, failed to parse %s", animationFile.c_str()); std::string errorFile = paths.getStringValue("sprites") + paths.getStringValue("spriteErrorFile"); @@ -157,7 +157,7 @@ void SpriteDef::loadImageSet(XML::Node node, const std::string &palettes) auto imageSet = resman->getImageSet(imageSrc, width, height); if (!imageSet) { - logger->error(strprintf("Couldn't load imageset (%s)!", + Log::critical(strprintf("Couldn't load imageset (%s)!", imageSrc.c_str())); } @@ -174,16 +174,16 @@ void SpriteDef::loadAction(XML::Node node, int variant_offset) auto si = mImageSets.find(imageSetName); if (si == mImageSets.end()) { - logger->log("Warning: imageset \"%s\" not defined in %s", - imageSetName.c_str(), getIdPath().c_str()); + Log::warn("imageset \"%s\" not defined in %s", + imageSetName.c_str(), getIdPath().c_str()); return; } ImageSet *imageSet = si->second; if (actionName == SpriteAction::INVALID) { - logger->log("Warning: Unknown action \"%s\" defined in %s", - actionName.c_str(), getIdPath().c_str()); + Log::warn("Unknown action \"%s\" defined in %s", + actionName.c_str(), getIdPath().c_str()); return; } auto *action = new Action; @@ -215,8 +215,8 @@ void SpriteDef::loadAnimation(XML::Node animationNode, if (directionType == DIRECTION_INVALID) { - logger->log("Warning: Unknown direction \"%s\" used in %s", - directionName.c_str(), getIdPath().c_str()); + Log::warn("Unknown direction \"%s\" used in %s", + directionName.c_str(), getIdPath().c_str()); return; } @@ -239,7 +239,7 @@ void SpriteDef::loadAnimation(XML::Node animationNode, if (index < 0) { - logger->log("No valid value for 'index'"); + Log::info("No valid value for 'index'"); continue; } @@ -247,7 +247,7 @@ void SpriteDef::loadAnimation(XML::Node animationNode, if (!img) { - logger->log("No image at index %d", index + variant_offset); + Log::info("No image at index %d", index + variant_offset); continue; } @@ -260,7 +260,7 @@ void SpriteDef::loadAnimation(XML::Node animationNode, if (start < 0 || end < 0) { - logger->log("No valid value for 'start' or 'end'"); + Log::info("No valid value for 'start' or 'end'"); continue; } @@ -270,7 +270,7 @@ void SpriteDef::loadAnimation(XML::Node animationNode, if (!img) { - logger->log("No image at index %d", start + variant_offset); + Log::info("No image at index %d", start + variant_offset); break; } @@ -295,8 +295,8 @@ void SpriteDef::includeSprite(XML::Node includeNode) if (processedFiles.find(filename) != processedFiles.end()) { - logger->log("Error, Tried to include %s which already is included.", - filename.c_str()); + Log::info("Error, Tried to include %s which already is included.", + filename.c_str()); return; } processedFiles.insert(filename); @@ -306,7 +306,7 @@ void SpriteDef::includeSprite(XML::Node includeNode) if (!rootNode || rootNode.name() != "sprite") { - logger->log("Error, no sprite root node in %s", filename.c_str()); + Log::info("Error, no sprite root node in %s", filename.c_str()); return; } diff --git a/src/resources/theme.cpp b/src/resources/theme.cpp index 8e4a07be..0c332902 100644 --- a/src/resources/theme.cpp +++ b/src/resources/theme.cpp @@ -25,7 +25,6 @@ #include "configuration.h" #include "log.h" -#include "textrenderer.h" #include "resources/dye.h" #include "resources/image.h" @@ -75,7 +74,7 @@ ThemeInfo::ThemeInfo(const std::string &path) if (rootNode.attribute("name", name) && !name.empty()) this->doc = std::move(doc); else - logger->log("Error: Theme '%s' has no name!", path.c_str()); + Log::error("Theme '%s' has no name!", path.c_str()); } std::string ThemeInfo::getFullPath() const @@ -228,15 +227,14 @@ void Skin::updateAlpha(float alpha) Theme::Theme(const ThemeInfo &themeInfo) : mThemePath(themeInfo.getFullPath()) - , mProgressColors(THEME_PROG_END) { listen(Event::ConfigChannel); readTheme(themeInfo); if (mPalettes.empty()) { - logger->log("Error, theme did not define any palettes: %s", - themeInfo.getPath().c_str()); + Log::info("Error, theme did not define any palettes: %s", + themeInfo.getPath().c_str()); // Avoid crashing mPalettes.emplace_back(THEME_COLORS_END); @@ -377,9 +375,12 @@ void Theme::drawSkin(Graphics *graphics, SkinType type, const WidgetState &state getSkin(type).draw(graphics, state); } -void Theme::drawProgressBar(Graphics *graphics, const gcn::Rectangle &area, - const gcn::Color &color, float progress, - const std::string &text) const +void Theme::drawProgressBar(Graphics *graphics, + const gcn::Rectangle &area, + const gcn::Color &color, + float progress, + const std::string &text, + ProgressPalette progressType) const { gcn::Font *oldFont = graphics->getFont(); gcn::Color oldColor = graphics->getColor(); @@ -408,17 +409,21 @@ void Theme::drawProgressBar(Graphics *graphics, const gcn::Rectangle &area, { if (auto skinState = skin.getState(widgetState.flags)) { - auto font = skinState->textFormat.bold ? boldFont : gui->getFont(); + const TextFormat *textFormat = &skinState->textFormat; + + if (progressType < THEME_PROG_END && mProgressTextFormats[progressType]) + textFormat = &(*mProgressTextFormats[progressType]); + + auto font = textFormat->bold ? boldFont : gui->getFont(); const int textX = area.x + area.width / 2; const int textY = area.y + (area.height - font->getHeight()) / 2; - TextRenderer::renderText(graphics, - text, - textX, - textY, - gcn::Graphics::CENTER, - font, - skinState->textFormat); + graphics->drawText(text, + textX, + textY, + gcn::Graphics::CENTER, + font, + *textFormat); } } @@ -479,7 +484,7 @@ static bool check(bool value, const char *msg, ...) { va_list ap; va_start(ap, msg); - logger->vlog(msg, ap); + Log::vinfo(msg, ap); va_end(ap); } return !value; @@ -487,9 +492,9 @@ static bool check(bool value, const char *msg, ...) bool Theme::readTheme(const ThemeInfo &themeInfo) { - logger->log("Loading %s theme from '%s'...", - themeInfo.getName().c_str(), - themeInfo.getPath().c_str()); + Log::info("Loading %s theme from '%s'...", + themeInfo.getName().c_str(), + themeInfo.getPath().c_str()); XML::Node rootNode = themeInfo.getDocument().rootNode(); @@ -507,10 +512,10 @@ bool Theme::readTheme(const ThemeInfo &themeInfo) else if (childNode.name() == "icon") readIconNode(childNode); else - logger->log("Theme: Unknown node '%s'!", childNode.name().data()); + Log::info("Theme: Unknown node '%s'!", childNode.name().data()); } - logger->log("Finished loading theme."); + Log::info("Finished loading theme."); for (auto &[_, skin] : mSkins) skin.updateAlpha(mAlpha); @@ -588,9 +593,8 @@ static void readSkinStateRectNode(XML::Node node, SkinState &state) node.attribute("fill", rect.filled); } -static void readSkinStateTextNode(XML::Node node, SkinState &state) +static void readTextNode(XML::Node node, TextFormat &textFormat) { - auto &textFormat = state.textFormat; node.attribute("bold", textFormat.bold); node.attribute("color", textFormat.color); node.attribute("outlineColor", textFormat.outlineColor); @@ -625,7 +629,7 @@ void Theme::readSkinStateNode(XML::Node node, Skin &skin) const else if (childNode.name() == "rect") readSkinStateRectNode(childNode, state); else if (childNode.name() == "text") - readSkinStateTextNode(childNode, state); + readTextNode(childNode, state.textFormat); } skin.addState(std::move(state)); @@ -689,7 +693,7 @@ void Theme::readSkinStateImgNode(XML::Node node, SkinState &state) const border.right = right; border.top = top; border.bottom = bottom; - border.image = image->getSubImage(x, y, width, height); + border.image.reset(image->getSubImage(x, y, width, height)); node.attribute("fill", border.fillMode); } @@ -705,7 +709,7 @@ inline void fromString(const char *str, gcn::Color &value) if (strlen(str) < 7 || str[0] != '#') { error: - logger->log("Error, invalid theme color palette: %s", str); + Log::info("Error, invalid theme color palette: %s", str); value = gcn::Color(0, 0, 0); return; } @@ -788,6 +792,7 @@ static int readColorId(const std::string &id) "WHISPER_TAB", "BACKGROUND", "HIGHLIGHT", + "HIGHLIGHT_TEXT", "TAB_FLASH", "SHOP_WARNING", "ITEM_EQUIPPED", @@ -873,7 +878,7 @@ void Theme::readPaletteNode(XML::Node node) { int paletteId; if (node.attribute("id", paletteId) && static_cast<size_t>(paletteId) != mPalettes.size()) - logger->log("Theme: Non-consecutive palette 'id' attribute with value %d!", paletteId); + Log::info("Theme: Non-consecutive palette 'id' attribute with value %d!", paletteId); Palette &palette = mPalettes.emplace_back(THEME_COLORS_END); @@ -882,7 +887,7 @@ void Theme::readPaletteNode(XML::Node node) if (childNode.name() == "color") readColorNode(childNode, palette); else - logger->log("Theme: Unknown node '%s'!", childNode.name().data()); + Log::info("Theme: Unknown node '%s'!", childNode.name().data()); } } @@ -916,5 +921,15 @@ void Theme::readProgressBarNode(XML::Node node) if (check(id >= 0, "Theme: 'progress' element has unknown 'id' attribute: '%s'!", idStr.c_str())) return; - mProgressColors[id] = std::make_unique<DyePalette>(node.getProperty("color", std::string())); + std::string color; + if (node.attribute("color", color)) + mProgressColors[id] = std::make_unique<DyePalette>(color); + + for (auto childNode : node.children()) + { + if (childNode.name() == "text") + readTextNode(childNode, mProgressTextFormats[id].emplace()); + else + Log::info("Theme: Unknown node '%s' in progressbar!", childNode.name().data()); + } } diff --git a/src/resources/theme.h b/src/resources/theme.h index bfd3b33a..fbcb263b 100644 --- a/src/resources/theme.h +++ b/src/resources/theme.h @@ -30,6 +30,7 @@ #include "resources/image.h" #include "utils/xml.h" +#include <array> #include <map> #include <memory> #include <optional> @@ -227,6 +228,7 @@ class Theme : public EventListener WHISPER_TAB, BACKGROUND, HIGHLIGHT, + HIGHLIGHT_TEXT, TAB_FLASH, SHOP_WARNING, ITEM_EQUIPPED, @@ -283,7 +285,7 @@ class Theme : public EventListener static const gcn::Color &getThemeColor(int type); static gcn::Color getProgressColor(int type, float progress); - + const Palette &getPalette(size_t index) const; /** @@ -305,7 +307,8 @@ class Theme : public EventListener const gcn::Rectangle &area, const gcn::Color &color, float progress, - const std::string &text = std::string()) const; + const std::string &text = std::string(), + ProgressPalette progressType = ProgressPalette::THEME_PROG_END) const; const Skin &getSkin(SkinType skinType) const; @@ -357,5 +360,6 @@ class Theme : public EventListener float mAlpha = 1.0; std::vector<Palette> mPalettes; - std::vector<std::unique_ptr<DyePalette>> mProgressColors; + std::array<std::unique_ptr<DyePalette>, THEME_PROG_END> mProgressColors; + std::array<std::optional<TextFormat>, THEME_PROG_END> mProgressTextFormats; }; diff --git a/src/sdlgraphics.cpp b/src/sdlgraphics.cpp index 9256471a..7d75e7f2 100644 --- a/src/sdlgraphics.cpp +++ b/src/sdlgraphics.cpp @@ -72,16 +72,17 @@ std::unique_ptr<Graphics> SDLGraphics::create(SDL_Window *window, const VideoSet SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, rendererFlags); if (!renderer) { - logger->error(strprintf("Failed to create renderer: %s", + Log::critical(strprintf("Failed to create renderer: %s", SDL_GetError())); return {}; } - return std::make_unique<SDLGraphics>(renderer); + return std::make_unique<SDLGraphics>(window, renderer); } -SDLGraphics::SDLGraphics(SDL_Renderer *renderer) - : mRenderer(renderer) +SDLGraphics::SDLGraphics(SDL_Window *window, SDL_Renderer *renderer) + : mWindow(window) + , mRenderer(renderer) { Image::setRenderer(mRenderer); @@ -90,25 +91,25 @@ SDLGraphics::SDLGraphics(SDL_Renderer *renderer) SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND); if (const char *driver = SDL_GetCurrentVideoDriver()) - logger->log("Using video driver: %s", driver); + Log::info("Using video driver: %s", driver); else - logger->log("Using video driver: not initialized"); + Log::info("Using video driver: not initialized"); SDL_RendererInfo info; if (SDL_GetRendererInfo(renderer, &info) == 0) { - logger->log("Using renderer: %s", info.name); - - logger->log("The renderer is a software fallback: %s", - (info.flags & SDL_RENDERER_SOFTWARE) ? "yes" : "no"); - logger->log("The renderer is hardware accelerated: %s", - (info.flags & SDL_RENDERER_ACCELERATED) ? "yes" : "no"); - logger->log("Vsync: %s", - (info.flags & SDL_RENDERER_PRESENTVSYNC) ? "on" : "off"); - logger->log("Renderer supports rendering to texture: %s", - (info.flags & SDL_RENDERER_TARGETTEXTURE) ? "yes" : "no"); - logger->log("Max texture size: %dx%d", - info.max_texture_width, info.max_texture_height); + Log::info("Using renderer: %s", info.name); + + Log::info("The renderer is a software fallback: %s", + (info.flags & SDL_RENDERER_SOFTWARE) ? "yes" : "no"); + Log::info("The renderer is hardware accelerated: %s", + (info.flags & SDL_RENDERER_ACCELERATED) ? "yes" : "no"); + Log::info("Vsync: %s", + (info.flags & SDL_RENDERER_PRESENTVSYNC) ? "on" : "off"); + Log::info("Renderer supports rendering to texture: %s", + (info.flags & SDL_RENDERER_TARGETTEXTURE) ? "yes" : "no"); + Log::info("Max texture size: %dx%d", + info.max_texture_width, info.max_texture_height); } } @@ -245,6 +246,7 @@ void SDLGraphics::drawRescaledImagePattern(const Image *image, void SDLGraphics::updateScreen() { SDL_RenderPresent(mRenderer); + SDL_ShowWindow(mWindow); } void SDLGraphics::windowToLogical(int windowX, int windowY, diff --git a/src/sdlgraphics.h b/src/sdlgraphics.h index 7cdea414..057fcdc3 100644 --- a/src/sdlgraphics.h +++ b/src/sdlgraphics.h @@ -33,7 +33,7 @@ public: static std::unique_ptr<Graphics> create(SDL_Window *window, const VideoSettings &settings); - SDLGraphics(SDL_Renderer *renderer); + SDLGraphics(SDL_Window *window, SDL_Renderer *renderer); ~SDLGraphics() override; void setVSync(bool sync) override; @@ -83,5 +83,6 @@ protected: void updateClipRect() override; private: + SDL_Window *mWindow = nullptr; SDL_Renderer *mRenderer = nullptr; }; diff --git a/src/sound.cpp b/src/sound.cpp index c97951a3..20d3810a 100644 --- a/src/sound.cpp +++ b/src/sound.cpp @@ -64,11 +64,11 @@ void Sound::init() if (mInstalled) return; - logger->log("Sound::init() Initializing sound..."); + Log::info("Sound::init() Initializing sound..."); if (SDL_InitSubSystem(SDL_INIT_AUDIO) == -1) { - logger->log("Sound::init() Failed to initialize audio subsystem"); + Log::info("Sound::init() Failed to initialize audio subsystem"); return; } @@ -78,8 +78,8 @@ void Sound::init() MIX_DEFAULT_CHANNELS, audioBuffer); if (res < 0) { - logger->log("Sound::init Could not initialize audio: %s", - Mix_GetError()); + Log::info("Sound::init Could not initialize audio: %s", + Mix_GetError()); return; } @@ -122,18 +122,18 @@ void Sound::info() case AUDIO_S16MSB: format = "S16MSB"; break; } - logger->log("Sound::info() SDL_mixer: %i.%i.%i (compiled)", + Log::info("Sound::info() SDL_mixer: %i.%i.%i (compiled)", compiledVersion.major, compiledVersion.minor, compiledVersion.patch); - logger->log("Sound::info() SDL_mixer: %i.%i.%i (linked)", + Log::info("Sound::info() SDL_mixer: %i.%i.%i (linked)", linkedVersion->major, linkedVersion->minor, linkedVersion->patch); - logger->log("Sound::info() Driver: %s", driver); - logger->log("Sound::info() Format: %s", format); - logger->log("Sound::info() Rate: %i", rate); - logger->log("Sound::info() Channels: %i", channels); + Log::info("Sound::info() Driver: %s", driver); + Log::info("Sound::info() Format: %s", format); + Log::info("Sound::info() Rate: %i", rate); + Log::info("Sound::info() Channels: %i", channels); } void Sound::setMusicVolume(int volume) @@ -173,7 +173,7 @@ void Sound::stopMusic() if (!mInstalled) return; - logger->log("Sound::stopMusic()"); + Log::info("Sound::stopMusic()"); haltMusic(); } @@ -201,7 +201,7 @@ void Sound::fadeOutMusic(int ms) if (!mInstalled) return; - logger->log("Sound::fadeOutMusic() Fading-out (%i ms)", ms); + Log::info("Sound::fadeOutMusic() Fading-out (%i ms)", ms); if (mMusic) { @@ -260,7 +260,7 @@ void Sound::playSfx(const std::string &path, int x, int y) if (ResourceRef<SoundEffect> sound = resman->getSoundEffect(tmpPath)) { - logger->log("Sound::playSfx() Playing: %s", path.c_str()); + Log::info("Sound::playSfx() Playing: %s", path.c_str()); int vol = 120; if (local_player && (x > 0 || y > 0)) @@ -299,7 +299,7 @@ void Sound::close() return; haltMusic(); - logger->log("Sound::close() Shutting down sound..."); + Log::info("Sound::close() Shutting down sound..."); Mix_CloseAudio(); mInstalled = false; diff --git a/src/text.cpp b/src/text.cpp index 4698aa87..14ffed18 100644 --- a/src/text.cpp +++ b/src/text.cpp @@ -23,7 +23,6 @@ #include "text.h" #include "textmanager.h" -#include "textrenderer.h" #include "gui/gui.h" @@ -94,6 +93,7 @@ void Text::adviseXY(int x, int y) void Text::draw(gcn::Graphics *graphics, int xOff, int yOff) { + auto g = static_cast<Graphics *>(graphics); if (mIsSpeech) { WidgetState state; @@ -103,7 +103,7 @@ void Text::draw(gcn::Graphics *graphics, int xOff, int yOff) state.height = mHeight + 10; auto theme = gui->getTheme(); - theme->drawSkin(static_cast<Graphics *>(graphics), SkinType::SpeechBubble, state); + theme->drawSkin(g, SkinType::SpeechBubble, state); /* if (mWidth >= 15) @@ -115,7 +115,7 @@ void Text::draw(gcn::Graphics *graphics, int xOff, int yOff) */ } - TextRenderer::renderText(graphics, mText, + g->drawText(mText, mX - xOff, mY - yOff, gcn::Graphics::LEFT, *mColor, mFont, !mIsSpeech, true); } diff --git a/src/textparticle.cpp b/src/textparticle.cpp index eb477217..4f6f1df4 100644 --- a/src/textparticle.cpp +++ b/src/textparticle.cpp @@ -21,7 +21,7 @@ #include "textparticle.h" -#include "textrenderer.h" +#include "graphics.h" #include <guichan/color.hpp> @@ -47,7 +47,7 @@ bool TextParticle::draw(Graphics *graphics, int offsetX, int offsetY) const gcn::Color color = *mColor; color.a = getCurrentAlpha() * 255; - TextRenderer::renderText(graphics, mText, + graphics->drawText(mText, screenX, screenY, gcn::Graphics::CENTER, color, mTextFont, mOutline, false); diff --git a/src/textrenderer.h b/src/textrenderer.h deleted file mode 100644 index de4fcff2..00000000 --- a/src/textrenderer.h +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Text Renderer - * Copyright (C) 2009 The Mana World Development Team - * Copyright (C) 2009-2012 The Mana Developers - * - * This file is part of The Mana Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#pragma once - -#include "resources/theme.h" - -#include <guichan/exception.hpp> -#include <guichan/font.hpp> - -/** - * Class for text rendering which can apply an outline and shadow. - */ -class TextRenderer -{ -public: - /** - * Renders a specified text. - */ - static void renderText(gcn::Graphics *graphics, - const std::string &text, - int x, int y, - gcn::Graphics::Alignment alignment, - const gcn::Color &color, - gcn::Font *font, - bool outline = false, - bool shadow = false, - const std::optional<gcn::Color> &outlineColor = {}, - const std::optional<gcn::Color> &shadowColor = {}) - { - switch (alignment) - { - case gcn::Graphics::LEFT: - break; - case gcn::Graphics::CENTER: - x -= font->getWidth(text) / 2; - break; - case gcn::Graphics::RIGHT: - x -= font->getWidth(text); - break; - default: - throw GCN_EXCEPTION("Unknown alignment."); - } - - // Text shadow - if (shadow) - { - if (shadowColor) - { - graphics->setColor(*shadowColor); - } - else - { - auto sc = Theme::getThemeColor(Theme::SHADOW); - sc.a = color.a / 2; - graphics->setColor(sc); - } - - if (outline) - font->drawString(graphics, text, x + 2, y + 2); - else - font->drawString(graphics, text, x + 1, y + 1); - } - - if (outline) - { - /* - graphics->setColor(guiPalette->getColor(Palette::OUTLINE, - alpha/4)); - // TODO: Reanable when we can draw it nicely in software mode - font->drawString(graphics, text, x + 2, y + 2); - font->drawString(graphics, text, x + 1, y + 2); - font->drawString(graphics, text, x + 2, y + 1); - */ - - // Text outline - if (outlineColor) - { - graphics->setColor(*outlineColor); - } - else - { - auto oc = Theme::getThemeColor(Theme::OUTLINE); - oc.a = color.a; - graphics->setColor(oc); - } - - font->drawString(graphics, text, x + 1, y); - font->drawString(graphics, text, x - 1, y); - font->drawString(graphics, text, x, y + 1); - font->drawString(graphics, text, x, y - 1); - } - - graphics->setColor(color); - font->drawString(graphics, text, x, y); - } - - /** - * Renders a specified text. - */ - static void renderText(gcn::Graphics *graphics, - const std::string &text, - int x, - int y, - gcn::Graphics::Alignment align, - gcn::Font *font, - const TextFormat &format) - { - renderText(graphics, - text, - x, - y, - align, - format.color, - font, - format.outlineColor.has_value(), - format.shadowColor.has_value(), - format.outlineColor, - format.shadowColor); - } -}; diff --git a/src/units.cpp b/src/units.cpp index ee8fa6ea..1ec81cb0 100644 --- a/src/units.cpp +++ b/src/units.cpp @@ -123,8 +123,8 @@ void Units::readUnitNode(XML::Node node, const std::string &filename) } else { - logger->log("Error bad unit count: %d for %s in %s", - ul.count, ul.symbol.c_str(), bu.symbol.c_str()); + Log::info("Error bad unit count: %d for %s in %s", + ul.count, ul.symbol.c_str(), bu.symbol.c_str()); } } } @@ -139,7 +139,7 @@ void Units::readUnitNode(XML::Node node, const std::string &filename) else if (type == "currency") units[UNIT_CURRENCY] = ud; else - logger->log("Error unknown unit type: %s in %s", type.c_str(), filename.c_str()); + Log::info("Error unknown unit type: %s in %s", type.c_str(), filename.c_str()); } diff --git a/src/utils/mutex.h b/src/utils/mutex.h index a0c72e95..b6c4e88d 100644 --- a/src/utils/mutex.h +++ b/src/utils/mutex.h @@ -75,13 +75,13 @@ inline Mutex::~Mutex() inline void Mutex::lock() { if (SDL_mutexP(mMutex) == -1) - logger->log("Mutex locking failed: %s", SDL_GetError()); + Log::info("Mutex locking failed: %s", SDL_GetError()); } inline void Mutex::unlock() { if (SDL_mutexV(mMutex) == -1) - logger->log("Mutex unlocking failed: %s", SDL_GetError()); + Log::info("Mutex unlocking failed: %s", SDL_GetError()); } diff --git a/src/utils/sha256.cpp b/src/utils/sha256.cpp index 0e44af7a..a1339d14 100644 --- a/src/utils/sha256.cpp +++ b/src/utils/sha256.cpp @@ -3,7 +3,7 @@ * Copyright (C) 2008-2009 The Mana World Development Team * Copyright (C) 2009-2012 The Mana Developers * - * This file has been slighly modified as part of The Mana Client. + * This file has been slightly modified as part of The Mana Client. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as diff --git a/src/utils/stringutils.cpp b/src/utils/stringutils.cpp index 05b6982c..7b05b365 100644 --- a/src/utils/stringutils.cpp +++ b/src/utils/stringutils.cpp @@ -152,6 +152,32 @@ bool getBoolFromString(std::string text, bool def) return def; } +// Overload for std::vector<int> to parse comma-separated integers +void fromString(const char *str, std::vector<int> &value) +{ + value.clear(); + + const char *p = str; + while (*p) + { + while (*p == ' ' || *p == ',') + ++p; // skip spaces and commas + if (!*p) + break; + char *end = nullptr; + int v = static_cast<int>(strtol(p, &end, 10)); + if (end != p) + { + value.push_back(v); + p = end; + } + else + { + ++p; // skip invalid character to avoid infinite loop + } + } +} + std::string autocomplete(const std::vector<std::string> &candidates, std::string base) { diff --git a/src/utils/stringutils.h b/src/utils/stringutils.h index 53c36bc6..885ddcb8 100644 --- a/src/utils/stringutils.h +++ b/src/utils/stringutils.h @@ -117,9 +117,18 @@ std::string &removeColors(std::string &msg); /** * Returns whether a string starts with a given prefix. */ -inline bool startsWith(const std::string &str, const char *prefix) +inline bool startsWith(std::string_view str, std::string_view prefix) { - return str.rfind(prefix, 0) == 0; + return str.substr(0, prefix.size()) == prefix; +} + +/** + * Returns whether a string ends with a given suffix. + */ +inline bool endsWith(std::string_view str, std::string_view suffix) +{ + return str.size() >= suffix.size() && + str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0; } /** @@ -193,6 +202,8 @@ inline void fromString(const char *str, bool &value) value = getBoolFromString(str); } +void fromString(const char *str, std::vector<int> &value); + template<typename T> struct FromString<T, std::enable_if_t<std::is_enum_v<T>>> { diff --git a/src/utils/xml.cpp b/src/utils/xml.cpp index c408c9c2..34bcc52b 100644 --- a/src/utils/xml.cpp +++ b/src/utils/xml.cpp @@ -43,13 +43,13 @@ namespace XML auto *context = static_cast<XMLContext*>(ctx); if (context) - logger->log("Error in XML file '%s' on line %d", - context->file.c_str(), error->line); + Log::info("Error in XML file '%s' on line %d", + context->file.c_str(), error->line); else - logger->log("Error in unknown XML file on line %d", - error->line); + Log::info("Error in unknown XML file on line %d", + error->line); - logger->log("%s", error->message); + Log::info("%s", error->message); // No need to keep errors around xmlCtxtResetLastError(error->ctxt); @@ -76,11 +76,11 @@ namespace XML SDL_free(data); if (!mDoc) - logger->log("Error parsing XML file %s", filename.c_str()); + Log::info("Error parsing XML file %s", filename.c_str()); } else { - logger->log("Error loading %s: %s", filename.c_str(), SDL_GetError()); + Log::info("Error loading %s: %s", filename.c_str(), SDL_GetError()); } xmlSetStructuredErrorFunc(nullptr, xmlLogger); @@ -109,7 +109,7 @@ namespace XML mWriter = xmlNewTextWriterFilename(fileName.c_str(), 0); if (!mWriter) { - logger->log("Error creating XML writer for file %s", fileName.c_str()); + Log::info("Error creating XML writer for file %s", fileName.c_str()); return; } diff --git a/src/utils/zlib.cpp b/src/utils/zlib.cpp index f78b235e..08281bcc 100644 --- a/src/utils/zlib.cpp +++ b/src/utils/zlib.cpp @@ -107,19 +107,19 @@ int inflateMemory(unsigned char *in, unsigned int inLength, { if (ret == Z_MEM_ERROR) { - logger->log("Error: Out of memory while decompressing data!"); + Log::error("Out of memory while decompressing data!"); } else if (ret == Z_VERSION_ERROR) { - logger->log("Error: Incompatible zlib version!"); + Log::error("Incompatible zlib version!"); } else if (ret == Z_DATA_ERROR) { - logger->log("Error: Incorrect zlib compressed data!"); + Log::error("Incorrect zlib compressed data!"); } else { - logger->log("Error: Unknown error while decompressing data!"); + Log::error("Unknown error while decompressing data!"); } free(out); diff --git a/src/video.cpp b/src/video.cpp index 7ab21d12..c71a9097 100644 --- a/src/video.cpp +++ b/src/video.cpp @@ -65,7 +65,7 @@ Graphics *Video::initialize(const VideoSettings &settings) if (!initDisplayModes()) { - logger->log("Failed to initialize display modes: %s", SDL_GetError()); + Log::info("Failed to initialize display modes: %s", SDL_GetError()); } SDL_DisplayMode displayMode; @@ -81,7 +81,7 @@ Graphics *Video::initialize(const VideoSettings &settings) if (SDL_GetClosestDisplayMode(mSettings.display, &requestedMode, &displayMode) == nullptr) { - logger->log("SDL_GetClosestDisplayMode failed: %s, falling back to borderless mode", SDL_GetError()); + Log::info("SDL_GetClosestDisplayMode failed: %s, falling back to borderless mode", SDL_GetError()); mSettings.windowMode = WindowMode::WindowedFullscreen; } } @@ -92,6 +92,10 @@ Graphics *Video::initialize(const VideoSettings &settings) switch (mSettings.windowMode) { case WindowMode::Windowed: + // In windowed mode, the window is initially created hidden, we'll show + // it once we have finished setting it up and done an initial paint to + // avoid startup flicker on X11 and Windows. + windowFlags |= SDL_WINDOW_HIDDEN; break; case WindowMode::Fullscreen: windowFlags |= SDL_WINDOW_FULLSCREEN; @@ -99,6 +103,10 @@ Graphics *Video::initialize(const VideoSettings &settings) break; case WindowMode::WindowedFullscreen: windowFlags |= SDL_WINDOW_FULLSCREEN_DESKTOP; + // On Windows, fullscreen desktop with OpenGL actually flickers worse + // when the window is initially hidden. + if (!mSettings.openGL) + windowFlags |= SDL_WINDOW_HIDDEN; videoMode = "windowed fullscreen"; break; } @@ -106,10 +114,10 @@ Graphics *Video::initialize(const VideoSettings &settings) if (mSettings.openGL) windowFlags |= SDL_WINDOW_OPENGL; - logger->log("Setting video mode %dx%d %s", - mSettings.width, - mSettings.height, - videoMode); + Log::info("Setting video mode %dx%d %s", + mSettings.width, + mSettings.height, + videoMode); mWindow = SDL_CreateWindow("Mana", SDL_WINDOWPOS_UNDEFINED, @@ -120,8 +128,7 @@ Graphics *Video::initialize(const VideoSettings &settings) if (!mWindow) { - logger->error(strprintf("Failed to create window: %s", - SDL_GetError())); + Log::critical(strprintf("Failed to create window: %s", SDL_GetError())); return nullptr; } @@ -131,7 +138,7 @@ Graphics *Video::initialize(const VideoSettings &settings) { if (SDL_SetWindowDisplayMode(mWindow, &displayMode) != 0) { - logger->log("SDL_SetWindowDisplayMode failed: %s", SDL_GetError()); + Log::info("SDL_SetWindowDisplayMode failed: %s", SDL_GetError()); } } @@ -144,7 +151,7 @@ Graphics *Video::initialize(const VideoSettings &settings) mGraphics = OpenGLGraphics::create(mWindow, mSettings); if (!mGraphics) { - logger->log("Failed to create OpenGL context, falling back to SDL renderer: %s", + Log::info("Failed to create OpenGL context, falling back to SDL renderer: %s", SDL_GetError()); mSettings.openGL = false; } @@ -170,7 +177,7 @@ bool Video::apply(const VideoSettings &settings) SDL_DisplayMode displayMode; if (SDL_GetWindowDisplayMode(mWindow, &displayMode) != 0) { - logger->error(strprintf("SDL_GetCurrentDisplayMode failed: %s", SDL_GetError())); + Log::critical(strprintf("SDL_GetCurrentDisplayMode failed: %s", SDL_GetError())); return false; } @@ -188,7 +195,7 @@ bool Video::apply(const VideoSettings &settings) if (SDL_SetWindowDisplayMode(mWindow, &displayMode) != 0) { - logger->error(strprintf("SDL_SetWindowDisplayMode failed: %s", SDL_GetError())); + Log::critical(strprintf("SDL_SetWindowDisplayMode failed: %s", SDL_GetError())); return false; } } @@ -209,7 +216,7 @@ bool Video::apply(const VideoSettings &settings) if (SDL_SetWindowFullscreen(mWindow, windowFlags) != 0) { - logger->error(strprintf("SDL_SetWindowFullscreen failed: %s", SDL_GetError())); + Log::critical(strprintf("SDL_SetWindowFullscreen failed: %s", SDL_GetError())); return false; } @@ -235,12 +242,12 @@ bool Video::apply(const VideoSettings &settings) return true; } -void Video::windowSizeChanged(int width, int height) +void Video::updateWindowSize() { - mSettings.width = width; - mSettings.height = height; - - mGraphics->updateSize(width, height, mSettings.scale()); + SDL_GetWindowSize(mWindow, &mSettings.width, &mSettings.height); + mGraphics->updateSize(mSettings.width, + mSettings.height, + mSettings.scale()); } bool Video::initDisplayModes() diff --git a/src/video.h b/src/video.h index 47aed627..03e0dc4f 100644 --- a/src/video.h +++ b/src/video.h @@ -89,9 +89,9 @@ public: bool apply(const VideoSettings &settings); /** - * Handle a change in window size, possibly adjusting the scale. + * Handles a change in window size, possibly adjusting the scale. */ - void windowSizeChanged(int width, int height); + void updateWindowSize(); const DisplayMode &desktopDisplayMode() const { |