From b1b9a503256dfcf5a6ac6488032af070b0f21c3a Mon Sep 17 00:00:00 2001
From: Arkhan <49446701+DamianQualshy@users.noreply.github.com>
Date: Fri, 28 Jun 2024 00:28:34 +0200
Subject: [PATCH] G2O 0.2.1
Init commit
---
README.md | 6 +
gamemode/client/chat.nut | 532 +++++++++++++++++++++
gamemode/client/gui.nut | 55 +++
gamemode/client/login.nut | 77 +++
gamemode/client/main.nut | 137 ++++++
gamemode/client/playerlist.nut | 415 ++++++++++++++++
gamemode/client/visual.nut | 246 ++++++++++
gamemode/import.xml | 29 ++
gamemode/server/acp.nut | 459 ++++++++++++++++++
gamemode/server/chat.nut | 135 ++++++
gamemode/server/login.nut | 124 +++++
gamemode/server/main.nut | 77 +++
gamemode/shared/anims.nut | 318 ++++++++++++
gamemode/shared/class.nut | 460 ++++++++++++++++++
gamemode/shared/packets.nut | 15 +
gamemode/shared/text.nut | 119 +++++
lib/file.nut | 140 ++++++
lib/gui-framework/abstract/alignment.nut | 16 +
lib/gui-framework/abstract/base.nut | 255 ++++++++++
lib/gui-framework/abstract/margin.nut | 45 ++
lib/gui-framework/abstract/offset.nut | 36 ++
lib/gui-framework/abstract/orientation.nut | 16 +
lib/gui-framework/animation.nut | 210 ++++++++
lib/gui-framework/elements/bar.nut | 257 ++++++++++
lib/gui-framework/elements/button.nut | 122 +++++
lib/gui-framework/elements/checkbox.nut | 104 ++++
lib/gui-framework/elements/collection.nut | 99 ++++
lib/gui-framework/elements/draw.nut | 391 +++++++++++++++
lib/gui-framework/elements/gridlist.nut | 495 +++++++++++++++++++
lib/gui-framework/elements/input.nut | 263 ++++++++++
lib/gui-framework/elements/multidraw.nut | 235 +++++++++
lib/gui-framework/elements/radiobutton.nut | 62 +++
lib/gui-framework/elements/range.nut | 324 +++++++++++++
lib/gui-framework/elements/scrollbar.nut | 324 +++++++++++++
lib/gui-framework/elements/slider.nut | 121 +++++
lib/gui-framework/elements/tabpanel.nut | 406 ++++++++++++++++
lib/gui-framework/elements/texture.nut | 225 +++++++++
lib/gui-framework/elements/tooltip.nut | 129 +++++
lib/gui-framework/elements/window.nut | 160 +++++++
lib/gui-framework/examples/bar.nut | 31 ++
lib/gui-framework/examples/button.nut | 46 ++
lib/gui-framework/examples/checkbox.nut | 10 +
lib/gui-framework/examples/draw.nut | 46 ++
lib/gui-framework/examples/gridlist.nut | 204 ++++++++
lib/gui-framework/examples/input.nut | 68 +++
lib/gui-framework/examples/multidraw.nut | 20 +
lib/gui-framework/examples/radiobutton.nut | 26 +
lib/gui-framework/examples/range.nut | 27 ++
lib/gui-framework/examples/scrollbar.nut | 9 +
lib/gui-framework/examples/slider.nut | 13 +
lib/gui-framework/examples/tabpanel.nut | 82 ++++
lib/gui-framework/examples/texture.nut | 53 ++
lib/gui-framework/examples/tooltip.nut | 62 +++
lib/gui-framework/examples/window.nut | 55 +++
lib/gui-framework/gui.xml | 33 ++
lib/gui-framework/main.nut | 44 ++
lib/gui-framework/multiple_inheritance.nut | 22 +
lib/gui-framework/utility.nut | 109 +++++
lib/gui-framework/vector.nut | 11 +
59 files changed, 8610 insertions(+)
create mode 100644 gamemode/client/chat.nut
create mode 100644 gamemode/client/gui.nut
create mode 100644 gamemode/client/login.nut
create mode 100644 gamemode/client/main.nut
create mode 100644 gamemode/client/playerlist.nut
create mode 100644 gamemode/client/visual.nut
create mode 100644 gamemode/import.xml
create mode 100644 gamemode/server/acp.nut
create mode 100644 gamemode/server/chat.nut
create mode 100644 gamemode/server/login.nut
create mode 100644 gamemode/server/main.nut
create mode 100644 gamemode/shared/anims.nut
create mode 100644 gamemode/shared/class.nut
create mode 100644 gamemode/shared/packets.nut
create mode 100644 gamemode/shared/text.nut
create mode 100644 lib/file.nut
create mode 100644 lib/gui-framework/abstract/alignment.nut
create mode 100644 lib/gui-framework/abstract/base.nut
create mode 100644 lib/gui-framework/abstract/margin.nut
create mode 100644 lib/gui-framework/abstract/offset.nut
create mode 100644 lib/gui-framework/abstract/orientation.nut
create mode 100644 lib/gui-framework/animation.nut
create mode 100644 lib/gui-framework/elements/bar.nut
create mode 100644 lib/gui-framework/elements/button.nut
create mode 100644 lib/gui-framework/elements/checkbox.nut
create mode 100644 lib/gui-framework/elements/collection.nut
create mode 100644 lib/gui-framework/elements/draw.nut
create mode 100644 lib/gui-framework/elements/gridlist.nut
create mode 100644 lib/gui-framework/elements/input.nut
create mode 100644 lib/gui-framework/elements/multidraw.nut
create mode 100644 lib/gui-framework/elements/radiobutton.nut
create mode 100644 lib/gui-framework/elements/range.nut
create mode 100644 lib/gui-framework/elements/scrollbar.nut
create mode 100644 lib/gui-framework/elements/slider.nut
create mode 100644 lib/gui-framework/elements/tabpanel.nut
create mode 100644 lib/gui-framework/elements/texture.nut
create mode 100644 lib/gui-framework/elements/tooltip.nut
create mode 100644 lib/gui-framework/elements/window.nut
create mode 100644 lib/gui-framework/examples/bar.nut
create mode 100644 lib/gui-framework/examples/button.nut
create mode 100644 lib/gui-framework/examples/checkbox.nut
create mode 100644 lib/gui-framework/examples/draw.nut
create mode 100644 lib/gui-framework/examples/gridlist.nut
create mode 100644 lib/gui-framework/examples/input.nut
create mode 100644 lib/gui-framework/examples/multidraw.nut
create mode 100644 lib/gui-framework/examples/radiobutton.nut
create mode 100644 lib/gui-framework/examples/range.nut
create mode 100644 lib/gui-framework/examples/scrollbar.nut
create mode 100644 lib/gui-framework/examples/slider.nut
create mode 100644 lib/gui-framework/examples/tabpanel.nut
create mode 100644 lib/gui-framework/examples/texture.nut
create mode 100644 lib/gui-framework/examples/tooltip.nut
create mode 100644 lib/gui-framework/examples/window.nut
create mode 100644 lib/gui-framework/gui.xml
create mode 100644 lib/gui-framework/main.nut
create mode 100644 lib/gui-framework/multiple_inheritance.nut
create mode 100644 lib/gui-framework/utility.nut
create mode 100644 lib/gui-framework/vector.nut
diff --git a/README.md b/README.md
index ff450ff..34e5187 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,8 @@
# Gothic-Homecoming
The Gothic Homecoming gamemode is based on how the 2011's Gothic Multiplayer worked, where you simply join a server and choose a class.
+
+# Features
+- Class choice on join
+- Animation window
+- Player Visual change
+- Global chat for everyone
\ No newline at end of file
diff --git a/gamemode/client/chat.nut b/gamemode/client/chat.nut
new file mode 100644
index 0000000..065506c
--- /dev/null
+++ b/gamemode/client/chat.nut
@@ -0,0 +1,532 @@
+/////////////////////////////////////////
+/// Defines
+/////////////////////////////////////////
+
+const CHAT_LINE_SIZE = 15;
+
+const CHAT_HISTORY_SIZE = 50;
+const CHAT_PLAYER_HISTORY_SIZE = 5;
+
+const CHAT_VISIBLE = true;
+const CHAT_ANIMATION_INTERVAL = 400;
+
+/////////////////////////////////////////
+/// Line types
+/////////////////////////////////////////
+
+class ChatLine
+{
+ constructor(r, g, b, text)
+ {
+ _line = Draw(0, 0, text);
+ _line.setColor(r, g, b);
+ }
+
+ function show()
+ {
+ _line.visible = true;
+ }
+
+ function hide()
+ {
+ _line.visible = false;
+ }
+
+ function update(x, y)
+ {
+ _line.setPositionPx(x, y);
+ }
+
+ function setAlpha(alpha)
+ {
+ _line.setAlpha(alpha)
+ }
+
+ function offset()
+ {
+ return _line.heightPx;
+ }
+
+ _line = null;
+ _animationBeginTime = -1;
+}
+
+//---------------------------------------
+
+class ChatPlayerLine extends ChatLine
+{
+ constructor(pid, r, g, b, text)
+ {
+ base.constructor(r, g, b, text);
+
+ local color = getPlayerColor(pid);
+ _nickname = Draw(0, 0, getPlayerName(pid) + ": ");
+ _nickname.setColor(color.r, color.g, color.b);
+ }
+
+ function show()
+ {
+ base.show();
+ _nickname.visible = true;
+ }
+
+ function hide()
+ {
+ base.hide();
+ _nickname.visible = false;
+ }
+
+ function update(x, y)
+ {
+ base.update(_nickname.widthPx + x, y);
+ _nickname.setPositionPx(x, y);
+ }
+
+ function setAlpha(alpha)
+ {
+ base.setAlpha(alpha)
+ _nickname.setAlpha(alpha)
+ }
+
+ function offset()
+ {
+ return _nickname.heightPx;
+ }
+
+ _nickname = null;
+}
+
+/////////////////////////////////////////
+/// Chat
+/////////////////////////////////////////
+
+Chat <- {
+ x = 5,
+ y = 5,
+ visible = CHAT_VISIBLE,
+
+ _lines = queue(),
+ _maxLines = CHAT_LINE_SIZE,
+
+ _historySize = CHAT_HISTORY_SIZE,
+ _location = 0,
+
+ _playerHistory = queue(),
+ _playerHistorySize = CHAT_PLAYER_HISTORY_SIZE,
+ _playerHistoryLocation = 0,
+
+ _animationInterval = CHAT_ANIMATION_INTERVAL.tofloat(),
+ _animationBeginTime = -1
+}
+
+//---------------------------------------
+
+function Chat::toggle()
+{
+ visible ? hide() : show();
+}
+
+//---------------------------------------
+
+function Chat::show()
+{
+ visible = true;
+
+ for (local i = firstVisibleLine(); i <= lastVisibleLine(); ++i)
+ _lines[i].show();
+}
+
+//---------------------------------------
+
+function Chat::hide()
+{
+ visible = false;
+
+ for (local i = firstVisibleLine(); i <= lastVisibleLine(); ++i)
+ _lines[i].hide();
+}
+
+//---------------------------------------
+
+function Chat::printPlayer(pid, r, g, b, msg)
+{
+ _printLine(ChatPlayerLine(pid, r, g, b, msg));
+
+ if (_playerHistorySize > 0)
+ {
+ _playerHistory.push(msg);
+
+ if (_playerHistory.len() > _playerHistorySize)
+ _playerHistory.pop();
+ }
+}
+
+//---------------------------------------
+
+function Chat::print(r, g, b, msg)
+{
+ _printLine(ChatLine(r, g, b, msg));
+}
+
+//---------------------------------------
+
+function Chat::_printLine(line)
+{
+ _lines.push(line);
+ if (visible) _lines[lastVisibleLine()].show();
+
+ if (_animationInterval > 0)
+ {
+ _lines[lastVisibleLine()].setAlpha(0);
+ _lines[lastVisibleLine()]._animationBeginTime = getTickCount();
+ }
+
+ if (_lines.len() > _maxLines)
+ {
+ _lines[firstVisibleLine() - 1].hide();
+
+ if (_lines.len() > _historySize)
+ _lines.pop();
+
+ if (_animationInterval > 0)
+ _animationBeginTime = getTickCount();
+ else
+ _calcPosition();
+ }
+ else
+ _calcPosition();
+}
+
+//---------------------------------------
+
+function Chat::_calcPosition()
+{
+ local offset = 0;
+
+ for (local i = firstVisibleLine(); i <= lastVisibleLine(); ++i)
+ {
+ local line = _lines[i];
+
+ if (visible) line.show();
+ line.update(x, y + offset);
+
+ offset += line.offset();
+ }
+
+ chatInputSetPosition(x, any(y + offset));
+}
+
+//---------------------------------------
+
+function Chat::setHistorySize(size)
+{
+ if (size >= _maxLines && _historySize > size)
+ {
+ local end = _lines.len() - size;
+
+ for (local i = 0; i < end; ++i)
+ _lines.pop();
+ }
+
+ _historySize = size;
+}
+
+//---------------------------------------
+
+function Chat::setMaxLines(maxLines)
+{
+ if (maxLines <= 0 || maxLines > 30)
+ return;
+
+ for (local i = firstVisibleLine(); i <= lastVisibleLine(); ++i)
+ _lines[i].hide();
+
+ _maxLines = maxLines;
+ _calcPosition();
+
+ if (_historySize < maxLines)
+ setHistorySize(maxLines);
+}
+
+//---------------------------------------
+
+function Chat::location()
+{
+ return _location;
+}
+
+//---------------------------------------
+
+function Chat::topLocation()
+{
+ local idx = _lines.len() - _maxLines;
+
+ if (idx < 0)
+ idx = 0;
+
+ return -idx;
+}
+
+//---------------------------------------
+
+function Chat::firstVisibleLine()
+{
+ local idx = _lines.len() - _maxLines + _location;
+
+ if (idx < 0)
+ idx = 0;
+
+ return idx;
+}
+
+//---------------------------------------
+
+function Chat::lastVisibleLine()
+{
+ local idx = _lines.len() - 1 + _location;
+
+ if (idx < 0)
+ idx = 0;
+
+ return idx;
+}
+
+//---------------------------------------
+
+function Chat::move(newLocation)
+{
+ if (_lines.len() < _maxLines)
+ return;
+
+ if ((_lines.len() - _maxLines + newLocation < 0) || (newLocation > 0))
+ return;
+
+ if (_location == newLocation)
+ return;
+
+ for (local i = firstVisibleLine(); i <= lastVisibleLine(); ++i)
+ _lines[i].hide();
+
+ _location = newLocation;
+ _calcPosition();
+}
+
+//---------------------------------------
+
+function Chat::setPlayerHistorySize(size)
+{
+ if (_playerHistorySize > size)
+ loadPlayerMessage(0);
+
+ _playerHistorySize = size;
+}
+
+//---------------------------------------
+
+function Chat::playerHistoryLocation()
+{
+ return _playerHistoryLocation;
+}
+
+//---------------------------------------
+
+function Chat::loadPlayerMessage(newLocation)
+{
+ if (!_playerHistory.len())
+ return;
+
+ if ((_playerHistory.len() + newLocation < 0) || (newLocation > 0))
+ return;
+
+ if (_playerHistoryLocation == newLocation)
+ return;
+
+ _playerHistoryLocation = newLocation;
+
+ if (newLocation != 0)
+ chatInputSetText(_playerHistory[_playerHistory.len() + newLocation]);
+ else
+ chatInputSetText("");
+}
+
+/////////////////////////////////////////
+/// Events
+/////////////////////////////////////////
+
+local function renderHandler()
+{
+ local now = getTickCount();
+
+ if (Chat._animationInterval <= 0)
+ return;
+
+ local deltaTime = (now - Chat._animationBeginTime) / Chat._animationInterval;
+ local firstVisibleLine = Chat.firstVisibleLine();
+
+ for (local i = 0; i < Chat._lines.len() - firstVisibleLine; ++i)
+ {
+ local line = Chat._lines[i + firstVisibleLine];
+
+ if (Chat._animationBeginTime != -1)
+ {
+ if (deltaTime < 1.0)
+ line.update(Chat.x, Chat.y + line.offset() * (i + 1) - line.offset() * deltaTime);
+ else
+ {
+ Chat._calcPosition();
+ Chat._animationBeginTime = -1;
+ }
+ }
+
+ if (line._animationBeginTime != -1)
+ {
+ local deltaTime = (now - line._animationBeginTime) / Chat._animationInterval;
+
+ if (deltaTime < 1.0)
+ line.setAlpha(255 * deltaTime);
+ else
+ {
+ line.setAlpha(255);
+ line._animationBeginTime = -1;
+ }
+ }
+ }
+}
+
+enableEvent_Render(true);
+addEventHandler("onRender", renderHandler);
+
+//---------------------------------------
+
+local function keyHandler(key)
+{
+ if (chatInputIsOpen())
+ {
+ switch (key)
+ {
+ case KEY_UP:
+ if (isKeyPressed(KEY_LCONTROL) || isKeyPressed(KEY_RCONTROL))
+ Chat.loadPlayerMessage(Chat.playerHistoryLocation() - 1);
+ else
+ Chat.move(Chat.location() - 1);
+ break;
+
+ case KEY_DOWN:
+ if (isKeyPressed(KEY_LCONTROL) || isKeyPressed(KEY_RCONTROL))
+ Chat.loadPlayerMessage(Chat.playerHistoryLocation() + 1);
+ else
+ Chat.move(Chat.location() + 1);
+ break;
+
+ case KEY_PRIOR:
+ Chat.move(Chat.topLocation());
+ break;
+
+ case KEY_NEXT:
+ Chat.move(0);
+ break;
+
+ case KEY_RETURN:
+ Chat.move(0);
+ chatInputSend();
+ Chat.loadPlayerMessage(0);
+
+ setFreeze(false);
+ Camera.enableMovement(true);
+ break;
+
+ case KEY_ESCAPE:
+ case KEY_TILDE:
+ chatInputClose();
+
+ setFreeze(false);
+ Camera.enableMovement(true);
+ break;
+
+ default:
+ playGesticulation(heroId);
+ break;
+ }
+ }
+ else
+ {
+ switch (key)
+ {
+ case KEY_T:
+ if (!isConsoleOpen() && Chat.visible)
+ {
+ chatInputOpen();
+
+ setFreeze(true);
+ Camera.enableMovement(false);
+ }
+ break;
+
+ case KEY_F9:
+ Chat.toggle();
+ break;
+ }
+ }
+}
+
+addEventHandler("onKey", keyHandler);
+
+//---------------------------------------
+
+local function commandHandler(cmd, param)
+{
+ try
+ param = param.tointeger()
+ catch (msg)
+ return;
+
+ switch (cmd)
+ {
+ case "chatlines":
+ Chat.setMaxLines(param);
+ break;
+
+ case "chatlimit":
+ Chat.setHistorySize(param);
+ break;
+
+ case "chatplayerlimit":
+ Chat.setPlayerHistorySize(param);
+ break
+ }
+}
+
+addEventHandler("onCommand", commandHandler)
+
+//---------------------------------------
+
+local function mouseWheelHandler(direction)
+{
+ if (!Chat.visible)
+ return;
+
+ if (!chatInputIsOpen())
+ return;
+
+ if (isKeyPressed(KEY_LCONTROL) || isKeyPressed(KEY_RCONTROL))
+ Chat.loadPlayerMessage(Chat.playerHistoryLocation() - direction);
+ else
+ Chat.move(Chat.location() - direction);
+}
+
+addEventHandler("onMouseWheel", mouseWheelHandler);
+
+//---------------------------------------
+
+local function messageHandler(pid, r, g, b, message)
+{
+ if (pid != -1)
+ Chat.printPlayer(pid, r, g, b, message);
+ else
+ Chat.print(r, g, b, message);
+}
+
+addEventHandler("onPlayerMessage", messageHandler);
+
+// Loaded
+print("chat.nut loaded...")
diff --git a/gamemode/client/gui.nut b/gamemode/client/gui.nut
new file mode 100644
index 0000000..66d14ad
--- /dev/null
+++ b/gamemode/client/gui.nut
@@ -0,0 +1,55 @@
+local windowM = GUI.Window(2400, 2500, 3500, 3500, "LOG_BACK.TGA"); //bg
+local logo = GUI.Draw(1650, 300, GUI_LOGO, windowM); //logo
+ logo.setFont("FONT_OLD_20_WHITE_HI.TGA");
+ logo.setColor(230,180,55);
+GUI.Texture(1390, 800, 1950, 2300, "LETTERS.TGA", windowM); //bg2
+GUI.Texture(50, 2300, 1210, 1100, "Map_DragonIsland.TGA", windowM); //map
+local czasgra = GUI.Draw(225, 300, "Czas gry " + getTime().hour + ":" + getTime().min, windowM); //czasgra
+local czasreal = GUI.Draw(225, 550, "Czas realny " + date().hour + ":" + date().min, windowM); //czasreal
+ czasgra.setColor(200,180,140);
+ czasreal.setColor(200,180,140);
+local charaB = GUI.Button(420, 1050, 540, 300, "", GUI_CHARA, windowM); //login
+local exit = GUI.Button(390, 1800, 535, 470, "", "Wyjście", windowM); //exit
+
+packet <- null;
+addEventHandler("onInit", function(){packet <- Packet();enableEvent_Render(true);});
+
+function openMENU(){setFreeze(true);windowM.setVisible(true);setCursorVisible(true);Camera.enableMovement(false);}
+function closeMENU(){setFreeze(false);windowM.setVisible(false);/*chara.setVisible(false);options.setVisible(false);*/setCursorVisible(false);Camera.enableMovement(true);}
+
+addEventHandler("GUI.onClick", function(self){
+ switch (self)
+ {
+
+ case exit:
+ closeMENU();
+ exitGame();
+ break
+ }
+});
+
+addEventHandler("GUI.onMouseIn", function(node){
+ if(node instanceof GUI.Button){
+ if(windowM.visible)
+ node.draw.setColor(60, 60, 180);
+ /*else if(options.visible || chara.visible)
+ node.draw.setColor(60, 180, 60);*/
+ }
+});
+
+addEventHandler("GUI.onMouseOut", function(node){
+ if(node instanceof GUI.Button){
+ if(windowM.visible)
+ node.draw.setColor(255, 255, 255);
+ }
+});
+
+addEventHandler("onKey", function(key){
+ if(key == KEY_ESCAPE){
+ if(windowM.visible){
+ openMENU();
+ }else{
+ closeMENU();
+ }
+ }
+});
diff --git a/gamemode/client/login.nut b/gamemode/client/login.nut
new file mode 100644
index 0000000..a5bdeeb
--- /dev/null
+++ b/gamemode/client/login.nut
@@ -0,0 +1,77 @@
+local window = GUI.Window(2400, 2500, 3500, 3500, "LOG_BACK.TGA"); //bg
+local logo = GUI.Draw(1700, 300, GUI_LOGO, window); //logo
+ logo.setFont("FONT_OLD_20_WHITE_HI.TGA");
+ logo.setColor(230,180,55);
+GUI.Texture(1390, 800, 1950, 2300, "LETTERS.TGA", window); //bg2
+GUI.Texture(50, 2300, 1210, 1100, "MAP_NEWWORLD_SEAMAP.TGA", window); //map
+local czasgra = GUI.Draw(225, 300, GUI_GTIME + getTime().hour + ":" + getTime().min, window); //czasgra
+local czasreal = GUI.Draw(225, 550, GUI_RTIME + date().hour + ":" + date().min, window); //czasreal
+ czasgra.setColor(200,180,140);
+ czasreal.setColor(200,180,140);
+local login = GUI.Button(410, 1050, 540, 300, "", GUI_LOGIN, window); //login
+local exit = GUI.Button(390, 1800, 535, 470, "", GUI_EXIT, window); //exit
+
+local textLog = GUI.Draw(2140,1100,GUI_TEXTLOG,window);
+local textPas = GUI.Draw(2125,1900,GUI_TEXTPAS,window);
+textLog.setFont("FONT_20_BOOK_HI.TGA");
+textPas.setFont("FONT_20_BOOK_HI.TGA");
+local inpLog = GUI.Input(1640,1400,1455,355,"INV_SLOT_FOCUS.TGA","FONT_DEFAULT.TGA", Input.Text, Align.Center, "...", 6, window);
+local inpPas = GUI.Input(1640,2200,1455,355,"INV_SLOT_FOCUS.TGA","FONT_DEFAULT.TGA", Input.Password, Align.Center, "...", 2, window);
+inpLog.maxLetters = 20;
+inpPas.maxLetters = 20;
+
+local loginbad = GUI.Draw(2140,1100,LOGIN_FAIL);
+
+// ================================================================================================= //
+
+addEventHandler("onInit", function(){
+ enableEvent_Render(true);
+ enableHud(HUD_HEALTH_BAR,false);
+ Camera.enableMovement(false);
+ Camera.setPosition(-14096.3,2758.05,-30978.6);
+ Camera.setRotation(0, 64, 0);
+ openLOGIN();
+
+ inpPas.setDisabled(false);
+ inpPas.setVisible(true);
+});
+
+function openLOGIN(){setFreeze(true);window.setVisible(true);setCursorVisible(true);}
+function closeLOGIN(){setFreeze(false);window.setVisible(false);loginbad.setVisible(false);setCursorVisible(false);enableHud(HUD_HEALTH_BAR,true);Camera.enableMovement(true);}
+
+// ================================================================================================= //
+
+addEventHandler("GUI.onClick", function(self){
+ switch (self)
+ {
+ case login:
+ packet.reset();
+ packet.writeUInt8(packets.checklog);
+ packet.writeString(inpLog.getText());
+ packet.writeString(md5(inpPas.getText()));
+ packet.send(RELIABLE);
+ break
+
+ case exit:
+ closeLOGIN();
+ exitGame();
+ break
+ }
+});
+
+addEventHandler("GUI.onMouseIn", function(node){
+if(node instanceof GUI.Button && window.visible)
+ node.draw.setColor(240, 60, 60);
+});
+
+addEventHandler("GUI.onMouseOut", function(node){
+if(node instanceof GUI.Button && window.visible)
+ node.draw.setColor(255, 255, 255);
+});
+
+addEventHandler("onPacket", function(packet){
+ local packetId = packet.readUInt8();
+ if(packetId == packets.logfail) {
+ loginbad.setVisible(true);
+ }
+});
diff --git a/gamemode/client/main.nut b/gamemode/client/main.nut
new file mode 100644
index 0000000..a3bcca6
--- /dev/null
+++ b/gamemode/client/main.nut
@@ -0,0 +1,137 @@
+addEvent("onChangeClass");
+
+mySerial <- "";
+myMac <- "";
+myIp <- "";
+
+local ui = {
+ name = Draw(150, 150, "..."),
+ guild = Draw(150, 325, "..."),
+ description = Draw(150, 500, "..."),
+ cselect = Draw(3000, 7600, MAIN_CSELECT)
+};
+ui.cselect.font = "FONT_OLD_20_WHITE_HI.tga";
+
+local toggleUi = function(flag) {
+ ui.name.visible = flag;
+ ui.guild.visible = flag;
+ ui.description.visible = flag;
+ ui.cselect.visible = flag;
+
+ setFreeze(flag);
+ Camera.enableMovement(!flag);
+}
+
+local isSelectingClass = false;
+local selectedClass = 0;
+local updateClassInfo = function() {
+ local info = classes[selectedClass];
+
+ ui.name.text = info.name;
+ ui.guild.text = info.guild;
+ ui.description.text = info.description;
+
+ clearInventory();
+ setPlayerPosition(heroId, info.spawn[0], info.spawn[1], info.spawn[2]);
+ setPlayerAngle(heroId, info.spawn[3]);
+
+ local x = info.spawn[0] + 200.0 * sin((3.14 / 180) * info.spawn[3]);
+ local z = info.spawn[2] + 200.0 * cos((3.14 / 180) * info.spawn[3]);
+ Camera.setPosition(x, info.spawn[1] + 20, z);
+ Camera.setRotation(0, info.spawn[3] + 180, 0);
+
+ packet.reset();
+ packet.writeUInt8(packets.select_class);
+ packet.writeUInt8(selectedClass);
+ packet.send(RELIABLE);
+}
+
+addEventHandler("onKey", function(key){
+ if(isSelectingClass) {
+ if(key == KEY_RETURN) {
+ clearInventory();
+ packet.reset();
+ packet.writeUInt8(packets.select_class);
+ packet.writeUInt8(selectedClass);
+ packet.writeUInt8(packets.selected_class);
+ packet.send(RELIABLE);
+
+ // show chat
+ toggleUi(false);
+ isSelectingClass = false;
+ }
+ else if(key == KEY_A) {
+ selectedClass -= 1;
+ if(selectedClass < 0)
+ selectedClass = classes.len() - 1;
+
+ while("serial" in classes[selectedClass]) {
+ if(classes[selectedClass].serial.find(mySerial) == null) {
+ selectedClass -= 1;
+ if(selectedClass < 0)
+ selectedClass = classes.len() - 1;
+ } else break;
+ }
+
+ updateClassInfo();
+ }
+ else if(key == KEY_D) {
+ selectedClass += 1;
+ if(selectedClass >= classes.len())
+ selectedClass = 0;
+
+ while("serial" in classes[selectedClass]) {
+ if(classes[selectedClass].serial.find(mySerial) == null) {
+ selectedClass += 1;
+ if(selectedClass >= classes.len())
+ selectedClass = 0;
+ } else break;
+ }
+
+ updateClassInfo();
+ }
+ }
+});
+
+local sjoin = Sound("DIA_1013_BANDIT_AMBUSH_01_01.WAV");
+local sjoin_human = Sound("DIA_ANDRE_JOIN_08_18.WAV");
+local sjoin_orc = Sound("DIA_URSHAK_HALLO_18_00.WAV");
+
+addEventHandler("onInit", function(){
+ clearMultiplayerMessages();
+ setKeyLayout(1);
+ enableEvent_Render(true);
+
+ disableKey(KEY_N, true);
+ disableKey(KEY_L, true);
+ disableKey(KEY_C, true);
+ disableKey(KEY_ESCAPE, true);
+});
+
+addEventHandler("onPacket", function(packet){
+ local packetId = packet.readUInt8();
+ if(packetId == packets.player_info) {
+ mySerial = packet.readString();
+ myIp = packet.readString();
+ myMac = packet.readString();
+ }
+ else if(packetId == packets.change_class) {
+ callEvent("onChangeClass", packet.readUInt8(), packet.readUInt8());
+ }
+ else if(packetId == packets.first_join) {
+ closeLOGIN();
+ isSelectingClass = true;
+ toggleUi(true);
+ updateClassInfo();
+ sjoin.play();
+ }
+ else if(packetId == packets.next_join) {
+ if(getPlayerInstance(heroId) == "PC_HERO"){
+ sjoin_human.play();
+ }
+ else if(getPlayerInstance(heroId) != "PC_HERO"){
+ sjoin_orc.play();
+ }
+ closeLOGIN();
+ }
+});
diff --git a/gamemode/client/playerlist.nut b/gamemode/client/playerlist.nut
new file mode 100644
index 0000000..83048f7
--- /dev/null
+++ b/gamemode/client/playerlist.nut
@@ -0,0 +1,415 @@
+/////////////////////////////////////////
+/// Defines
+/////////////////////////////////////////
+
+local MAX_PLAYERS = 30;
+
+/////////////////////////////////////////
+/// Player list class
+/////////////////////////////////////////
+
+PlayerList <- {
+ // Private
+ _hostname = null,
+ _items = array(getMaxSlots(), null),
+ _headers = [],
+ _backgrounds = [],
+ _lineHeightPx = -1,
+ _begin = 0,
+ _size = 0,
+
+ // Public
+ visible = false,
+ x = -1,
+ y = 100,
+ width = -1,
+ height = -1,
+
+ // Constans
+ ID = -1,
+ NICKNAME = -1,
+ GUILD = -1,
+}
+
+//---------------------------------------
+
+function PlayerList::constructor()
+{
+ // List draw
+ _hostname = Draw(0, 0, getHostname());
+ _hostname.font = "FONT_OLD_20_WHITE_HI.TGA";
+ _hostname.setPositionPx(nax(4096 - _hostname.width / 2), y / 2);
+
+ ID = registerColumn("ID", 200);
+ NICKNAME = registerColumn("Nick", 2000);
+ GUILD = registerColumn("Gildia", 1200);
+ // Add more columns after this line...
+
+ resize();
+
+ // Create textures
+ registerTexture("MENU_INGAME.TGA", function ()
+ {
+ tex.setPositionPx(PlayerList.x - 25,PlayerList.y - 15);
+ tex.setSizePx(PlayerList.width + 50, PlayerList.height + 30);
+ });
+
+ // Add more textures after this line...
+
+ // Top
+ foreach (header in _headers)
+ header.draw.top();
+}
+
+//---------------------------------------
+
+function PlayerList::registerColumn(name, width)
+{
+ local draw = Draw(0, 0, name);
+ draw.setColor(255, 255, 0);
+
+ _headers.push({
+ name = name,
+ width = width,
+ draw = draw,
+ })
+
+ return _headers.len() - 1;
+}
+
+//---------------------------------------
+
+function PlayerList::registerTexture(name, resize)
+{
+ local tex = Texture(0, 0, 0, 0, name);
+ local bg = {
+ resize = resize,
+ tex = tex,
+ }
+
+ bg.resize();
+ _backgrounds.push(bg);
+}
+
+//---------------------------------------
+
+function PlayerList::getItem(pid)
+{
+ return _items[pid];
+}
+
+//---------------------------------------
+
+function PlayerList::toggle()
+{
+ visible ? hide() : show();
+}
+
+//---------------------------------------
+
+function PlayerList::show()
+{
+ if (visible) return;
+ visible = true;
+
+ _hostname.visible = true;
+
+ foreach (header in _headers)
+ header.draw.visible = true;
+
+ foreach (bg in _backgrounds)
+ bg.tex.visible = true;
+
+ _showActive();
+}
+
+//---------------------------------------
+
+function PlayerList::hide()
+{
+ if (!visible) return;
+ visible = false;
+
+ _hostname.visible = false;
+
+ foreach (header in _headers)
+ header.draw.visible = false;
+
+ foreach (bg in _backgrounds)
+ bg.tex.visible = false;
+
+ _hideActive();
+}
+
+//---------------------------------------
+
+function PlayerList::scroll(value)
+{
+ _hideActive();
+
+ // Calculate new begin
+ local len = _size - MAX_PLAYERS + 1;
+ if (len < 0) len = 0;
+
+ _begin -= value;
+
+ if (_begin < 0) _begin = 0;
+ else if (_begin > len) _begin = len;
+
+ _showActive();
+}
+
+//---------------------------------------
+
+function PlayerList::insert(pid)
+{
+ if (pid >= _items.len()) return;
+
+ local playerItem = heroId != pid ? PlayerListItem(pid, 255, 255, 255) : PlayerListItem(pid, 255, 150, 0);
+
+ _items[pid] = playerItem;
+ ++_size;
+
+ return playerItem;
+}
+
+//---------------------------------------
+
+function PlayerList::remove(pid)
+{
+ if (pid >= _items.len()) return;
+
+ _items[pid] = null;
+ --_size;
+}
+
+//---------------------------------------
+
+function PlayerList::resize()
+{
+ local res = getResolution();
+ _lineHeightPx = _headers.top().draw.heightPx;
+
+ width = 0;
+ height = _lineHeightPx * MAX_PLAYERS;
+
+ foreach (header in _headers)
+ width += (nax(header.width) + header.draw.widthPx);
+
+ local headerX = x = (res.x - width) / 2.0;
+ local headerY = y;
+ local offset = _lineHeightPx;
+ local count = 0;
+
+ width = 0;
+ foreach (header in _headers)
+ {
+ header.draw.setPositionPx(headerX + width, headerY);
+ width += (nax(header.width) + header.draw.widthPx);
+ }
+
+ for (local i = _begin; i < _items.len() && count < MAX_PLAYERS - 1; ++i)
+ {
+ local item = _items[i];
+ if (!item) continue;
+
+ item.update(x, y + offset);
+
+ offset += item.offset();
+ ++count;
+ }
+
+ foreach (bg in _backgrounds)
+ bg.resize();
+}
+
+//---------------------------------------
+
+function PlayerList::_hideActive()
+{
+ local count = 0;
+
+ for (local i = _begin; i < _items.len() && count < MAX_PLAYERS - 1; ++i)
+ {
+ local item = _items[i];
+ if (!item) continue;
+
+ item.hide();
+ ++count;
+ }
+}
+
+//---------------------------------------
+
+function PlayerList::_showActive()
+{
+ local count = 0;
+ local offset = _lineHeightPx;
+
+ for (local i = _begin; i < _items.len() && count < MAX_PLAYERS - 1; ++i)
+ {
+ local item = _items[i];
+ if (!item) continue;
+
+ item.update(x, y + offset);
+ item.show();
+
+ offset += item.offset();
+ ++count;
+ }
+}
+
+/////////////////////////////////////////
+/// Player list item
+/////////////////////////////////////////
+
+class PlayerListItem
+{
+ constructor(pid, r, g, b)
+ {
+ columns = [];
+ visible = false;
+
+ foreach (header in PlayerList._headers)
+ {
+ local draw = Draw(0, 0, "");
+ draw.setColor(r, g, b);
+
+ columns.push(draw);
+ }
+ }
+
+ function show()
+ {
+ if (visible) return;
+ visible = true;
+
+ foreach (column in columns)
+ column.visible = true;
+ }
+
+ function hide()
+ {
+ if (!visible) return;
+ visible = false;
+
+ foreach (column in columns)
+ column.visible = false;
+ }
+
+ function offset()
+ {
+ return columns.top().heightPx;
+ }
+
+ function update(x, y)
+ {
+ local headers = PlayerList._headers;
+ local width = 0;
+
+ foreach (id, column in columns)
+ {
+ column.setPositionPx(x + width, y);
+ width += (nax(headers[id].width) + headers[id].draw.widthPx);
+ }
+ }
+
+ columns = null;
+ visible = false;
+}
+
+/////////////////////////////////////////
+/// Events
+/////////////////////////////////////////
+
+local function playerCreate(pid)
+{
+ local playerItem = PlayerList.insert(pid);
+
+ // Init item with default data
+ local color = getPlayerColor(pid);
+
+ playerItem.columns[PlayerList.ID].text = pid.tostring();
+ playerItem.columns[PlayerList.NICKNAME].text = getPlayerName(pid);
+ playerItem.columns[PlayerList.NICKNAME].setColor(color.r, color.g, color.b);
+ playerItem.columns[PlayerList.GUILD].text = "";
+}
+
+addEventHandler("onPlayerCreate", playerCreate);
+
+//---------------------------------------
+
+local function playerDestroy(pid)
+{
+ PlayerList.remove(pid);
+}
+
+addEventHandler("onPlayerDestroy", playerDestroy);
+
+//---------------------------------------
+
+local function playerGuild(pid, class_id)
+{
+ local playerItem = PlayerList.getItem(pid);
+ if (playerItem == null) return;
+
+ playerItem.columns[PlayerList.GUILD].text = classes[class_id].guild;
+}
+
+addEventHandler("onChangeClass", playerGuild);
+
+//---------------------------------------
+
+local function playerNickname(pid, name)
+{
+ local playerItem = PlayerList.getItem(pid);
+ if (playerItem == null) return;
+
+ playerItem.columns[PlayerList.NICKNAME].text = name;
+}
+
+addEventHandler("onPlayerChangeNickname", playerNickname);
+
+//---------------------------------------
+
+local function playerColor(pid, r, g, b)
+{
+ local playerItem = PlayerList.getItem(pid);
+ if (playerItem == null) return;
+
+ playerItem.columns[PlayerList.NICKNAME].setColor(r, g, b);
+}
+
+addEventHandler("onPlayerChangeColor", playerColor);
+
+//---------------------------------------
+
+local function keyHandler(key)
+{
+ if (key == KEY_F5 && !chatInputIsOpen())
+ PlayerList.toggle();
+}
+
+addEventHandler("onKey", keyHandler);
+
+//---------------------------------------
+
+local function mouseWheel(value)
+{
+ if (PlayerList.visible)
+ PlayerList.scroll(value);
+}
+
+addEventHandler("onMouseWheel", mouseWheel);
+
+//---------------------------------------
+
+local function resChange()
+{
+ PlayerList.resize();
+}
+
+addEventHandler("onChangeResolution", resChange);
+
+// Initialize PlayerList
+PlayerList.constructor();
diff --git a/gamemode/client/visual.nut b/gamemode/client/visual.nut
new file mode 100644
index 0000000..d8dbe9c
--- /dev/null
+++ b/gamemode/client/visual.nut
@@ -0,0 +1,246 @@
+local isOpen = false;
+local visual = {
+ body = {
+ model = ["HUM_BODY_BABE0", "HUM_BODY_NAKED0"],
+ tex = 10
+ },
+ head = {
+ model = ["HUM_HEAD_BALD","HUM_HEAD_FATBALD","HUM_HEAD_FIGHTER","HUM_HEAD_PONY","HUM_HEAD_PSIONIC","HUM_HEAD_THIEF", "HUM_HEAD_BABE", "HUM_HEAD_BABE1", "HUM_HEAD_BABE2", "HUM_HEAD_BABE3", "HUM_HEAD_BABE4", "HUM_HEAD_BABE5", "HUM_HEAD_BABE6", "HUM_HEAD_BABE7", "HUM_HEAD_BABE8", "HUM_HEAD_BABEHAIR"],
+ tex = 162
+ }
+};
+local mySetting = [
+ 1, 8, 3, 18 //body model, texture, head model, texture
+];
+
+local GUI = {
+ Header = Draw(6390, 4750, VIS_HEADER),
+ Head_Model = {
+ Left = Texture(5750, 5350, 150, 150, "L.tga"),
+ Right = Texture(7550, 5350, 150, 150, "R.tga"),
+ Text = Draw(6000, 5250, VIS_HMODEL)
+ },
+ Head_Texture = {
+ Left = Texture(5750, 5600, 150, 150, "L.tga"),
+ Right = Texture(7550, 5600, 150, 150, "R.tga"),
+ Text = Draw(6000, 5500, VIS_HTEX)
+ },
+ Body_Model = {
+ Left = Texture(5750, 5850, 150, 150, "L.tga"),
+ Right = Texture(7550, 5850, 150, 150, "R.tga"),
+ Text = Draw(6000, 5750, VIS_BMODEL)
+ },
+ Body_Texture = {
+ Left = Texture(5750, 6100, 150, 150, "L.tga"),
+ Right = Texture(7550, 6100, 150, 150, "R.tga"),
+ Text = Draw(6000, 6000, VIS_BTEX)
+ },
+ Exit = {
+ Button = Texture(6000, 3250, 1500, 1500, "MENU_MASKE.tga"),
+ Text = Draw(6390, 6350, VIS_EXIT)
+ }
+};
+
+GUI.Header.font = "FONT_OLD_20_WHITE_HI.tga";
+GUI.Head_Model.Text.font = "FONT_OLD_20_WHITE_HI.tga";
+GUI.Head_Texture.Text.font = "FONT_OLD_20_WHITE_HI.tga";
+GUI.Body_Model.Text.font = "FONT_OLD_20_WHITE_HI.tga";
+GUI.Body_Texture.Text.font = "FONT_OLD_20_WHITE_HI.tga";
+GUI.Exit.Text.font = "FONT_OLD_20_WHITE_HI.tga";
+
+addEventHandler("onKey", function(key){
+if(getPlayerInstance(heroId) == "PC_HERO"){
+ if(key == KEY_F8){
+ if(!isOpen){
+ openVisualMenu();
+ } else {
+ closeVisualMenu();
+
+ packet.reset();
+ local vis = getPlayerVisual(heroId);
+ packet.writeUInt8(packets.visual);
+ packet.writeString(vis.bodyModel);
+ packet.writeUInt8(vis.bodyTxt);
+ packet.writeString(vis.headModel);
+ packet.writeUInt8(vis.headTxt);
+ packet.send(RELIABLE);
+ }
+ setCursorVisible(isOpen);
+ }
+}
+});
+
+function openVisualMenu(){
+ Camera.enableMovement(false);
+ local pos = getPlayerPosition(heroId);
+ local angle = getPlayerAngle(heroId);
+ pos.x = pos.x + (sin(angle * 3.14 / 180.0) * 160);
+ pos.z = pos.z + (cos(angle * 3.14 / 180.0) * 170);
+ Camera.setPosition(pos.x, pos.y, pos.z);
+ Camera.setRotation(0, angle - 180, 0);
+ enableKeys(false);
+ setFreeze(true);
+ //playAni(heroId, "S_THRONE_S1");
+
+ isOpen = true;
+
+ GUI.Header.visible = true;
+
+ GUI.Head_Model.Left.visible = true;
+ GUI.Head_Model.Right.visible = true;
+ GUI.Head_Model.Text.visible = true;
+
+ GUI.Head_Texture.Left.visible = true;
+ GUI.Head_Texture.Right.visible = true;
+ GUI.Head_Texture.Text.visible = true;
+
+ GUI.Body_Model.Left.visible = true;
+ GUI.Body_Model.Right.visible = true;
+ GUI.Body_Model.Text.visible = true;
+
+ GUI.Body_Texture.Left.visible = true;
+ GUI.Body_Texture.Right.visible = true;
+ GUI.Body_Texture.Text.visible = true;
+
+ GUI.Exit.Button.visible = true;
+ //GUI.Exit.Text.visible = true;
+}
+function closeVisualMenu(){
+ Camera.enableMovement(true);
+ Camera.setTargetPlayer(heroId);
+ enableKeys(true);
+ setFreeze(false);
+ playAni(heroId, "S_RUN");
+
+ isOpen = false;
+
+ GUI.Header.visible = false;
+
+ GUI.Head_Model.Left.visible = false;
+ GUI.Head_Model.Right.visible = false;
+ GUI.Head_Model.Text.visible = false;
+
+ GUI.Head_Texture.Left.visible = false;
+ GUI.Head_Texture.Right.visible = false;
+ GUI.Head_Texture.Text.visible = false;
+
+ GUI.Body_Model.Left.visible = false;
+ GUI.Body_Model.Right.visible = false;
+ GUI.Body_Model.Text.visible = false;
+
+ GUI.Body_Texture.Left.visible = false;
+ GUI.Body_Texture.Right.visible = false;
+ GUI.Body_Texture.Text.visible = false;
+
+ GUI.Exit.Button.visible = false;
+ GUI.Exit.Text.visible = false;
+}
+
+local isInside = function(x1, y1, x2, y2, w, h){
+ if(x1 <= x2 + w && x1 >= x2 && y1 <= y2 + h && y1 >= y2)
+ return true;
+ else
+ return false;
+}
+local changeValue = function(id, val){
+ local value = mySetting[id];
+ value += val;
+
+ if(id == 0) {
+ if(value > visual.body.model.len()) value = 0;
+ else if(value < 0) value = visual.body.model.len() - 1;
+ }
+ else if(id == 1) {
+ if(value > visual.body.tex) value = 0;
+ else if(value < 0) value = visual.body.tex - 1;
+ }
+ else if(id == 2) {
+ if(value > visual.head.model.len()) value = 0;
+ else if(value < 0) value = visual.head.model.len() - 1;
+ }
+ else if(id == 3) {
+ if(value > visual.head.tex) value = 0;
+ else if(value < 0) value = visual.head.tex - 1;
+ }
+
+ mySetting[id] = value;
+ setPlayerVisual(heroId, visual.body.model[mySetting[0]], mySetting[1], visual.head.model[mySetting[2]], mySetting[3]);
+}
+
+local checkBodyModel = function(x, y){
+ local gui = GUI.Body_Model;
+
+ local left_pos = gui.Left.getPosition();
+ local left_size = gui.Left.getSize();
+ if(isInside(x, y, left_pos.x, left_pos.y, left_size.width, left_size.height)){
+ changeValue(0, -1);
+ return;
+ }
+ local right_pos = gui.Right.getPosition();
+ local right_size = gui.Right.getSize();
+ if(isInside(x, y, right_pos.x, right_pos.y, right_size.width, right_size.height)){
+ changeValue(0, 1);
+ return;
+ }
+}
+local checkBodyTex = function(x, y){
+ local gui = GUI.Body_Texture;
+
+ local left_pos = gui.Left.getPosition();
+ local left_size = gui.Left.getSize();
+ if(isInside(x, y, left_pos.x, left_pos.y, left_size.width, left_size.height)){
+ changeValue(1, -1);
+ return;
+ }
+ local right_pos = gui.Right.getPosition();
+ local right_size = gui.Right.getSize();
+ if(isInside(x, y, right_pos.x, right_pos.y, right_size.width, right_size.height)){
+ changeValue(1, 1);
+ return;
+ }
+}
+local checkHeadModel = function(x, y){
+ local gui = GUI.Head_Model;
+
+ local left_pos = gui.Left.getPosition();
+ local left_size = gui.Left.getSize();
+ if(isInside(x, y, left_pos.x, left_pos.y, left_size.width, left_size.height)){
+ changeValue(2, -1);
+ return;
+ }
+ local right_pos = gui.Right.getPosition();
+ local right_size = gui.Right.getSize();
+ if(isInside(x, y, right_pos.x, right_pos.y, right_size.width, right_size.height)){
+ changeValue(2, 1);
+ return;
+ }
+}
+local checkHeadTex = function(x, y){
+ local gui = GUI.Head_Texture;
+
+ local left_pos = gui.Left.getPosition();
+ local left_size = gui.Left.getSize();
+ if(isInside(x, y, left_pos.x, left_pos.y, left_size.width, left_size.height)){
+ changeValue(3, -1);
+ return;
+ }
+ local right_pos = gui.Right.getPosition();
+ local right_size = gui.Right.getSize();
+ if(isInside(x, y, right_pos.x, right_pos.y, right_size.width, right_size.height)){
+ changeValue(3, 1);
+ return;
+ }
+}
+
+addEventHandler("onMouseClick", function(btn){
+ if(isOpen){
+ if(btn == MOUSE_LMB){
+ local mouse = getCursorPosition();
+
+ checkBodyModel(mouse.x, mouse.y);
+ checkBodyTex(mouse.x, mouse.y);
+ checkHeadModel(mouse.x, mouse.y);
+ checkHeadTex(mouse.x, mouse.y);
+ }
+ }
+});
diff --git a/gamemode/import.xml b/gamemode/import.xml
new file mode 100644
index 0000000..0749683
--- /dev/null
+++ b/gamemode/import.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/gamemode/server/acp.nut b/gamemode/server/acp.nut
new file mode 100644
index 0000000..bbb2aad
--- /dev/null
+++ b/gamemode/server/acp.nut
@@ -0,0 +1,459 @@
+local Player = [];
+for (local i = 0; i < getMaxSlots(); ++i)
+ Player.push({rank = 0});
+
+enum LEVEL {
+ DOWO = 1,
+ MOD = 2,
+ ADMIN = 3,
+}
+
+local ADMIN_SERIAL = [
+ "60c5ac7101bcb18ad14d6f90de0838814bd261a" // Arkhan
+];
+
+local MOD_SERIAL = [
+ "62da690db19419764be78ac7e3414b00eeb7acd" // Sett
+];
+
+local DOWO_SERIAL = [
+ //"d78bf213615ff3bd3bb1b4187593f1936d6d73f" // Arkhan
+];
+
+local function isPlayerLogged(pid){
+ if(Players[pid].logged == 1)
+ return true;
+ else
+ return false;
+}
+
+function checkPermission (pid, level){
+ if (Player[pid].rank >= level)
+ return true;
+}
+
+local function cmd_error(pid, id){
+ if (!isPlayerLogged(id))
+ {
+ sendMessageToPlayer(pid, 255, 0, 0, ACP_ERROR);
+ return;
+ }
+}
+
+local cmd_acp = function(pid, params){
+ if (!checkPermission(pid, LEVEL.MOD)) return;
+ sendMessageToPlayer(pid, 0, 255, 0, ACP_HELP);
+}
+
+local cmd_color = function(pid, params){
+ if (!checkPermission(pid, LEVEL.MOD)) return;
+
+ local args = sscanf("dddd", params);
+ if (!args)
+ {
+ sendMessageToPlayer(pid, 255, 0, 0, ACP_PARCOLOR);
+ return;
+ }
+
+ local id = args[0];
+ local r = args[1];
+ local g = args[2];
+ local b = args[3];
+
+ cmd_error(pid, id);
+ setPlayerColor(id, r, g, b);
+
+ sendMessageToPlayer(pid, 0, 255, 0, ACP_MSGCOLOR + getPlayerName(id) + " (" + r + "," + g + "," + b + ")");
+}
+
+local cmd_name = function(pid, params){
+ if (!checkPermission(pid, LEVEL.DOWO)) return;
+
+ local args = sscanf("ds", params);
+ if (!args)
+ {
+ sendMessageToPlayer(pid, 255, 0, 0, ACP_PARNAME);
+ return;
+ }
+
+ local id = args[0];
+ local name = args[1];
+
+ cmd_error(pid, id);
+ setPlayerName(id, name);
+
+ sendMessageToPlayer(pid, 0, 255, 0, ACP_MSGNAME + getPlayerName(id) + " (" + name + ")");
+}
+
+local cmd_kick = function(pid, params){
+ if (!checkPermission(pid, LEVEL.MOD)) return;
+
+ local args = sscanf("ds", params);
+ if (!args)
+ {
+ sendMessageToPlayer(pid, 255, 0, 0, ACP_PARKICK);
+ return;
+ }
+
+ local id = args[0];
+ local reason = args[1];
+
+ cmd_error(pid, id);
+ kick(id, reason);
+
+ sendMessageToAll(255, 0, 0, ACP_MSGKICK + getPlayerName(id) + " - " + reason);
+}
+
+local cmd_kickall = function(pid, params){
+ if (!checkPermission(pid, LEVEL.ADMIN)) return;
+
+ local args = sscanf("s", params);
+ if (!args)
+ {
+ sendMessageToPlayer(pid, 255, 0, 0, ACP_PARKICKALL);
+ return;
+ }
+
+ local reason = args[0];
+
+ for(local i = 0; i < getMaxSlots(); ++i){
+ kick(i, reason);
+ }
+}
+
+local cmd_ban = function(pid, params){
+ if (!checkPermission(pid, LEVEL.ADMIN)) return;
+
+ local args = sscanf("dds", params);
+ if (!args)
+ {
+ sendMessageToPlayer(pid, 255, 0, 0, ACP_PARBAN);
+ return;
+ }
+
+ local id = args[0];
+ local minutes = args[1];
+ local reason = args[2];
+
+ cmd_error(pid, id);
+ ban(id, minutes, reason);
+
+ sendMessageToAll(255, 0, 0, ACP_MSGBAN + getPlayerName(id) + " - " + reason);
+}
+
+local cmd_tp = function(pid, params){
+ if (!checkPermission(pid, LEVEL.MOD)) return;
+
+ local args = sscanf("dd", params);
+ if (!args)
+ {
+ sendMessageToPlayer(pid, 255, 0, 0, ACP_PARTP);
+ return;
+ }
+
+ local from_id = args[0];
+ local to_id = args[1];
+
+ if (!isPlayerLogged(from_id) || !isPlayerLogged(to_id))
+ {
+ sendMessageToPlayer(pid, 255, 0, 0, ACP_ERROR);
+ return;
+ }
+
+ if (from_id == to_id)
+ {
+ sendMessageToPlayer(pid, 255, 0, 0, ACP_ERRORTP);
+ return;
+ }
+
+ local world = getPlayerWorld(to_id);
+ if (world != getPlayerWorld(from_id))
+ setPlayerWorld(from_id, world);
+
+ local pos = getPlayerPosition(to_id);
+ setPlayerPosition(from_id, pos.x + 10, pos.y + 2, pos.z + 10);
+
+ sendMessageToPlayer(pid, 0, 255, 0, ACP_MSGTP + getPlayerName(from_id) + " > " + getPlayerName(to_id));
+}
+
+local cmd_tpall = function(pid, params){
+ if (!checkPermission(pid, LEVEL.MOD)) return;
+
+ local args = sscanf("d", params);
+ if (!args)
+ {
+ sendMessageToPlayer(pid, 255, 0, 0, ACP_PARTPALL);
+ return;
+ }
+
+ local id = args[0];
+
+ cmd_error(pid, id);
+
+ for(local i = 0; i < getMaxSlots(); ++i){
+ local world = getPlayerWorld(id);
+ if (world != getPlayerWorld(i))
+ setPlayerWorld(i, world);
+
+ local pos = getPlayerPosition(id);
+ setPlayerPosition(i, pos.x + 10, pos.y + 2, pos.z + 10);
+ }
+ sendMessageToAll(0, 255, 0, ACP_MSGTPALL + getPlayerName(id));
+}
+
+local cmd_giveitem = function(pid, params){
+ if (!checkPermission(pid, LEVEL.MOD)) return;
+
+ local args = sscanf("dsd", params);
+ if (!args)
+ {
+ sendMessageToPlayer(pid, 255, 0, 0, ACP_PARGIVE);
+ return;
+ }
+
+ local id = args[0];
+ local instance = args[1].toupper();
+ local amount = args[2];
+
+ cmd_error(pid, id);
+ if (amount < 1) amount = 1;
+ giveItem(id, Items.id(instance), amount);
+
+ sendMessageToPlayer(id, 0, 255, 0, ACP_MSGGIVE + getPlayerName(pid) + "(" + instance + " x" + amount + ")");
+}
+
+local cmd_time = function(pid, params){
+ if (!checkPermission(pid, LEVEL.MOD)) return;
+
+ local args = sscanf("dd", params);
+ if (!args)
+ {
+ sendMessageToPlayer(pid, 255, 0, 0, ACP_PARTIME);
+ return;
+ }
+
+ local hour = args[0];
+ local min = args[1];
+
+ if (hour > 23) hour = 23;
+ else if (hour < 0) hour = 0;
+
+ if (min > 59) min = 59;
+ else if (min < 0) min = 0;
+
+ setTime(hour, min);
+ sendMessageToAll(0, 255, 0, ACP_MSGTIME + getPlayerName(pid) + " (" + hour + ":" + min + ")");
+}
+
+local cmd_scale = function(pid, params){
+ if (!checkPermission(pid, LEVEL.MOD)) return;
+
+ local args = sscanf("dfff", params);
+ if (!args)
+ {
+ sendMessageToPlayer(pid, 255, 0, 0, ACP_PARSCALE);
+ return;
+ }
+
+ local id = args[0];
+ local x = args[1];
+ local y = args[2];
+ local z = args[3];
+
+ cmd_error(pid, id);
+ setPlayerScale(id, x, y, z);
+
+ sendMessageToPlayer(pid, 0, 255, 0, ACP_MSGSCALE + getPlayerName(id) + " (" + x + " " + y + " " + z + ")");
+}
+
+local cmd_pos = function(pid, params){
+ if (!checkPermission(pid, LEVEL.MOD)) return;
+
+ local args = sscanf("s", params);
+ if (!args)
+ {
+ sendMessageToPlayer(pid, 255, 0, 0, ACP_PARPOS);
+ return;
+ }
+
+ local nazwa = args[0];
+
+ local vec = getPlayerPosition(pid);
+ local angle = getPlayerAngle(pid);
+
+ sendMessageToPlayer(pid, 0, 255, 0, ACP_MSGPOS + nazwa);
+}
+
+local cmd_promotion = function(pid, params){
+ if (!checkPermission(pid, LEVEL.DOWO)) return;
+
+ local args = sscanf("dd", params);
+ if (!args)
+ {
+ sendMessageToPlayer(pid, 255, 0, 0, ACP_PARPROMO);
+ return;
+ }
+
+ local id = args[0];
+ local cid = args[1];
+
+ cmd_error(pid, id);
+
+ local cid_old = Players[id].klasa;
+ local klasa_old = classes[cid_old].name;
+ local klasa = classes[cid].name;
+
+ classes[cid].func(id);
+ Players[id].klasa = cid;
+
+ sendMessageToPlayer(pid, 0, 255, 0, ACP_MSGPROMO + getPlayerName(pid) + "(" + klasa + ")");
+
+ packet.reset();
+ packet.writeUInt8(packets.change_class);
+ packet.writeUInt8(id);
+ packet.writeUInt8(cid);
+ for(local i = 0; i < getMaxSlots(); ++i){
+ if(isPlayerConnected(i))
+ packet.send(i, UNRELIABLE);
+ }
+}
+
+local cmd_classlist = function(pid){
+ if (!checkPermission(pid, LEVEL.DOWO)) return;
+
+ sendMessageToPlayer(pid, 0, 255, 0, "-=========== KLASY ===========-");
+ foreach (id, klasa in classes){
+ //for(local id = 0; id < classes.len(); ++id)
+ sendMessageToPlayer(pid, 0, 255, 0, "(" + id + ") " + klasa.name);
+ }
+ sendMessageToPlayer(pid, 0, 255, 0, "-=========== KLASY ===========-");
+}
+
+local cmd_glob = function(pid, params){
+ if (!checkPermission(pid, LEVEL.DOWO)) return;
+
+ sendMessageToAll(0, 200, 225, "(" + getPlayerName(pid) + ": " + params + ")");
+}
+
+local cmd_post = function(pid, params){
+ if (!checkPermission(pid, LEVEL.DOWO)) return;
+
+ sendMessageToAll(205, 133, 63, "#" + params + "#");
+}
+
+local cmd_gpw = function(pid, params){
+ if (!checkPermission(pid, LEVEL.DOWO)) return;
+
+ local gildia = classes[pid].guild;
+
+ for(local i = 0; i < getPlayersCount(); ++i){
+ if(classes[i].guild == gildia){
+ sendMessageToPlayer(i, 144, 86, 255, "(GILDIA) (" + getPlayerName(pid) + ": " + params + ")");
+ }
+ }
+}
+
+local cmd_apw = function(pid, params){
+ for(local i = 0; i < getMaxSlots(); ++i){
+ if(checkPermission(i, LEVEL.MOD)){
+ sendMessageToPlayer(i, 255, 86, 144, "(APW) (" + getPlayerName(pid) + "|"+pid+"): " + params);
+ }
+ }
+}
+
+local playerJoin = function(pid){
+ local playerSerial = getPlayerSerial(pid);
+
+ foreach (serial in ADMIN_SERIAL)
+ {
+ if (serial == playerSerial)
+ {
+ Player[pid].rank = LEVEL.ADMIN;
+ setPlayerColor(pid, 255, 0, 0);
+ return;
+ }
+ }
+ foreach (serial in MOD_SERIAL)
+ {
+ if (serial == playerSerial)
+ {
+ Player[pid].rank = LEVEL.MOD;
+ setPlayerColor(pid, 0, 255, 0);
+ return;
+ }
+ }
+ foreach (serial in DOWO_SERIAL)
+ {
+ if (serial == playerSerial)
+ {
+ Player[pid].rank = LEVEL.DOWO;
+ setPlayerColor(pid, 0, 0, 255);
+ return;
+ }
+ }
+}addEventHandler("onPlayerJoin", playerJoin);
+
+local playerDisconnect = function(pid, reason){
+ Player[pid].rank = 0;
+}addEventHandler("onPlayerDisconnect", playerDisconnect);
+
+addEventHandler("onPlayerCommand", function(pid, cmd, params){
+ cmd = cmd.tolower();
+ if(cmd == "acp"){
+ cmd_acp(pid, params);
+ }
+ else if(cmd == "color"){
+ cmd_color(pid, params)
+ }
+ else if(cmd == "name" || cmd == "nick"){
+ cmd_name(pid, params)
+ }
+ else if(cmd == "kick"){
+ cmd_kick(pid, params)
+ }
+ else if(cmd == "kickall"){
+ cmd_kickall(pid, params)
+ }
+ else if(cmd == "ban"){
+ cmd_ban(pid, params)
+ }
+ else if(cmd == "tp"){
+ cmd_tp(pid, params)
+ }
+ else if(cmd == "tpall"){
+ cmd_tpall(pid, params)
+ }
+ else if(cmd == "giveitem" || cmd == "give" || cmd == "item"){
+ cmd_giveitem(pid, params)
+ }
+ else if(cmd == "time"){
+ cmd_time(pid, params)
+ }
+ else if(cmd == "scale"){
+ cmd_scale(pid, params)
+ }
+ else if(cmd == "pos"){
+ cmd_pos(pid, params)
+ }
+ else if(cmd == "awans" || cmd == "promote" || cmd == "promo" || cmd == "awansuj"){
+ cmd_promotion(pid, params)
+ }
+ else if(cmd == "klasy" || cmd == "listaklas"){
+ cmd_classlist(pid)
+ }
+ else if(cmd == "g" || cmd == "global" || cmd == "gooc"){
+ cmd_glob(pid, params)
+ }
+ else if(cmd == "p" || cmd == "post" || cmd == "gdo"){
+ cmd_post(pid, params)
+ }
+ else if(cmd == "apw" || cmd == "apm" || cmd == "report"){
+ cmd_apw(pid, params)
+ }
+ else if(cmd == "gpw" || cmd == "gmsg" || cmd == "gildia"){
+ cmd_gpw(pid, params)
+ }
+ else if(cmd == "exit" || cmd == "q" || cmd == "quit"){
+ kick(pid, EXIT_KICK);
+ }
+});
diff --git a/gamemode/server/chat.nut b/gamemode/server/chat.nut
new file mode 100644
index 0000000..95c5352
--- /dev/null
+++ b/gamemode/server/chat.nut
@@ -0,0 +1,135 @@
+local CZAT_OOC = function(pid, params){
+ local send = getPlayerPosition(pid);
+ for(local i = 0; i < getMaxSlots(); ++i){
+ if(isPlayerConnected(i)){
+ local pos = getPlayerPosition(i);
+ if(getDistance3d(send.x, send.y, send.z, pos.x, pos.y, pos.z) <= 1500){
+ sendMessageToPlayer(i, 64, 178, 225, "(" + getPlayerName(pid) + " || " + pid + ") " + params);
+ }
+ }
+ }
+}
+
+local CZAT_ME = function(pid, params){
+ local send = getPlayerPosition(pid);
+ for(local i = 0; i < getMaxSlots(); ++i){
+ if(isPlayerConnected(i)){
+ local pos = getPlayerPosition(i);
+ if(getDistance3d(send.x, send.y, send.z, pos.x, pos.y, pos.z) <= 1500){
+ sendMessageToPlayer(i, 232, 116, 8, "#" + getPlayerName(pid) + " " + params + "#");
+ }
+ }
+ }
+}
+
+local CZAT_DO = function(pid, params){
+ local send = getPlayerPosition(pid);
+ for(local i = 0; i < getMaxSlots(); ++i){
+ if(isPlayerConnected(i)){
+ local pos = getPlayerPosition(i);
+ if(getDistance3d(send.x, send.y, send.z, pos.x, pos.y, pos.z) <= 1500){
+ sendMessageToPlayer(i, 32, 225, 127, "(" + getPlayerName(pid) + ") #" + params + "#");
+ }
+ }
+ }
+}
+
+local CZAT_K = function(pid, params){
+ local send = getPlayerPosition(pid);
+ for(local i = 0; i < getMaxSlots(); ++i){
+ if(isPlayerConnected(i)){
+ local pos = getPlayerPosition(i);
+ if(getDistance3d(send.x, send.y, send.z, pos.x, pos.y, pos.z) <= 2300){
+ sendMessageToPlayer(i, 200, 32, 32, getPlayerName(pid) + CHAT_SCREAM + params);
+ }else if(getDistance3d(send.x, send.y, send.z, pos.x, pos.y, pos.z) >= 2301 && getDistance3d(send.x, send.y, send.z, pos.x, pos.y, pos.z) <= 3000){
+ sendMessageToPlayer(i, 200, 32, 32, CHAT_DISTANCESCREAM + params);
+ }
+ }
+ }
+}
+
+local CZAT_SZ = function(pid, params){
+ local send = getPlayerPosition(pid);
+ for(local i = 0; i < getMaxSlots(); ++i){
+ if(isPlayerConnected(i)){
+ local pos = getPlayerPosition(i);
+ if(getDistance3d(send.x, send.y, send.z, pos.x, pos.y, pos.z) <= 500){
+ sendMessageToPlayer(i, 200, 200, 200, getPlayerName(pid) + CHAT_WHISPER + params);
+ }else if(getDistance3d(send.x, send.y, send.z, pos.x, pos.y, pos.z) >= 501 && getDistance3d(send.x, send.y, send.z, pos.x, pos.y, pos.z) <= 700){
+ sendMessageToPlayer(i, 200, 200, 200, CHAT_DISTANCEWHISPER + params);
+ }
+ }
+ }
+}
+
+local CZAT_PW = function(pid, params){
+ local par = sscanf("ds", params);
+ if(par){
+ if(isPlayerConnected(par[0])){
+ sendMessageToPlayer(par[0], 244, 144, 24, "(PW) (" + getPlayerName(pid) + "|"+pid+") << " + par[1]);
+ sendMessageToPlayer(pid, 224, 144, 64, "(PW) (" + getPlayerName(par[0]) + "|"+par[0]+") >> " + par[1]);
+ }
+ }
+}
+
+local CZAT_IC = function(pid, text){
+ local send = getPlayerPosition(pid);
+ for(local i = 0; i < getMaxSlots(); ++i){
+ if(isPlayerConnected(i)){
+ local pos = getPlayerPosition(i);
+ if(getDistance3d(send.x, send.y, send.z, pos.x, pos.y, pos.z) <= 1300){
+ sendMessageToPlayer(i, 255, 255, 255, getPlayerName(pid) + CHAT_SPEAK + text);
+ }else if(getDistance3d(send.x, send.y, send.z, pos.x, pos.y, pos.z) >= 1301 && getDistance3d(send.x, send.y, send.z, pos.x, pos.y, pos.z) <= 1500){
+ sendMessageToPlayer(i, 127, 127, 127, CHAT_DISTANCESPEAK + text);
+ }
+ }
+ }
+}
+
+addEventHandler("onPlayerMessage", function(pid, text){
+ strip(text);
+ local msgType = text.slice(0, 1);
+ local params = text.slice(1);
+ if(msgType == "@"){
+ CZAT_OOC(pid, params);
+ }
+ else if(msgType == "#"){
+ CZAT_ME(pid, params);
+ }
+ else if(msgType == "."){
+ CZAT_DO(pid, params);
+ }
+ else if(msgType == ","){
+ CZAT_SZ(pid, params);
+ }
+ else if(msgType == "!"){
+ CZAT_K(pid, params);
+ }
+ else if(msgType == "/"){
+ sendMessageToPlayer(pid, 255, 0, 0, ACP_ERROR2);
+ }
+ else
+ CZAT_IC(pid, text);
+});
+
+addEventHandler("onPlayerCommand", function(pid, cmd, params){
+ cmd = cmd.tolower();
+ if(cmd == "pw" || cmd == "pm"){
+ CZAT_PW(pid, params);
+ }
+ else if(cmd == "ooc" || cmd == "b"){
+ CZAT_OOC(pid, params);
+ }
+ else if(cmd == "me" || cmd == "ja"){
+ CZAT_ME(pid, params);
+ }
+ else if(cmd == "do"){
+ CZAT_DO(pid, params);
+ }
+ else if(cmd == "sz"){
+ CZAT_SZ(pid, params);
+ }
+ else if(cmd == "k"){
+ CZAT_K(pid, params);
+ }
+});
diff --git a/gamemode/server/login.nut b/gamemode/server/login.nut
new file mode 100644
index 0000000..288b5fa
--- /dev/null
+++ b/gamemode/server/login.nut
@@ -0,0 +1,124 @@
+addEventHandler("onPlayerJoin", function(pid){
+ if(getPlayerName(pid) == "Nickname"){
+ kick(pid, LOGIN_KICK);
+ } else
+ sendMessageToAll(128, 128, 128, getPlayerName(pid) + LOGIN_JOIN);
+});
+
+addEventHandler("onPlayerDisconnect", function(pid, reason){
+ if(Players[pid].logged == 1){
+ sendMessageToAll(128, 128, 128, getPlayerName(pid) + LOGIN_LEAVE);
+ SavePlayer(pid, login, password);
+ SavePlayerLogg(pid);
+ }
+});
+
+function LoadPlayer(pid, login, password)
+{
+ local myfile = io.file("database/players/" + login + "_data.txt", "r");
+ if (myfile.isOpen)
+ {
+ local password = myfile.read(io_type.LINE);
+ local pclass = myfile.read(io_type.LINE).tointeger();
+ if(pclass){
+ classes[pclass].func(pid);
+ Players[pid].klasa = pclass;
+ packet.reset();
+ packet.writeUInt8(packets.change_class);
+ packet.writeUInt8(pid);
+ packet.writeUInt8(pclass);
+ for(local i = 0; i < getMaxSlots(); ++i)
+ if(isPlayerConnected(i))
+ packet.send(i, UNRELIABLE);
+ }
+ local vis = sscanf("sdsd", myfile.read(io_type.LINE));
+ if(vis){
+ setPlayerVisual(pid, vis[0], vis[1], vis[2], vis[3]);
+ }
+ local pscale = sscanf("ffff", myfile.read(io_type.LINE));
+ if(pscale){
+ setPlayerScale(pid, pscale[0], pscale[1], pscale[2]);
+ setPlayerFatness(pid, pscale[3]);
+ }
+ local pos = sscanf("ffff", myfile.read(io_type.LINE));
+ if(pos){
+ setPlayerPosition(pid, pos[0], pos[1], pos[2]);
+ setPlayerAngle(pid, pos[3]);
+ }
+ myfile.close();
+ return true;
+ }
+ else
+ print(myfile.errorMsg);
+ return false;
+};
+
+function SavePlayer(pid, login, password)
+{
+ local myfile = io.file("database/players/" + login + "_data.txt", "w");
+ if (myfile.isOpen)
+ {
+ myfile.write(password + "\n");
+ local pclass = Players[pid].klasa;
+ myfile.write(pclass + "\n");
+ local vis = getPlayerVisual(pid);
+ myfile.write(vis.bodyModel + " " + vis.bodyTxt + " " + vis.headModel + " " + vis.headTxt + "\n");
+ local pscale = getPlayerScale(pid);
+ local pfat = getPlayerFatness(pid);
+ myfile.write(pscale.x + " " + pscale.y + " " + pscale.z + " " + pfat + "\n");
+ local pos = getPlayerPosition(pid);
+ local posa = getPlayerAngle(pid)
+ myfile.write(pos.x + " " + pos.y + " " + pos.z + " " + posa + "\n");
+ myfile.close();
+ }
+ else
+ print(myfile.errorMsg);
+};
+
+function SavePlayerLogg(pid)
+{
+ local myfile = io.file("database/players/" + getPlayerName(pid) + "_logg.txt", "a+");
+ if (myfile.isOpen)
+ {
+ local datas = date().day + "/" + date().month + " " + date().hour + ":" + date().min;
+ myfile.write(datas + " || " + getPlayerSerial(pid) + " | " + getPlayerIP(pid) + " | " + getPlayerMacAddr(pid) + "\n");
+ myfile.close();
+ }
+ else
+ print(myfile.errorMsg);
+};
+
+addEventHandler("onPacket", function(player, packet){
+ local packet_id = packet.readUInt8();
+ if(packet_id == packets.checklog) {
+ local _login = packet.readString(), _password = packet.readString();
+ if(!LoadPlayer(player, _login, _password)) {
+ packet.reset();
+ packet.writeUInt8(packets.first_join);
+ packet.send(player, RELIABLE);
+ setPlayerName(player, _login);
+ }
+ else {
+ local checkpass = io.file("database/players/" + login + "_data.txt", "r");
+ if (checkpass.isOpen)
+ {
+ local password = checkpass.read(io_type.LINE);
+ if(_login == getPlayerName(player) && _password == password) {
+ sendMessageToPlayer(player, 200, 200, 200, LOGIN_MESSAGE);
+ spawnPlayer(player);
+ LoadPlayer(player, _login, _password);
+ Players[player].logged = 1;
+ packet.reset();
+ packet.writeUInt8(packets.next_join);
+ packet.send(player, RELIABLE);
+ }
+ else {
+ packet.reset();
+ packet.writeUInt8(packets.logfail);
+ packet.send(player, RELIABLE);
+ checkpass.close();
+ }
+ }
+ }
+ }
+});
diff --git a/gamemode/server/main.nut b/gamemode/server/main.nut
new file mode 100644
index 0000000..0de1909
--- /dev/null
+++ b/gamemode/server/main.nut
@@ -0,0 +1,77 @@
+Players <- {};
+for(local i = 0; i < getMaxSlots(); ++i){
+ Players[i] <- {};
+ Players[i].klasa <- 0;
+ Players[i].logged <- 0;
+}
+
+addEventHandler("onPacket", function(player, packet){
+ local packet_id = packet.readUInt8();
+ if(packet_id == packets.select_class){
+ local cid = packet.readUInt8();
+ classes[cid].func(player);
+ Players[player].klasa = cid;
+
+ packet.reset();
+ packet.writeUInt8(packets.change_class);
+ packet.writeUInt8(player);
+ packet.writeUInt8(cid);
+ for(local i = 0; i < getMaxSlots(); ++i)
+ if(isPlayerConnected(i))
+ packet.send(i, UNRELIABLE);
+ }else if(packet_id == packets.visual){
+ local vis1 = packet.readString();
+ local vis2 = packet.readUInt8();
+ local vis3 = packet.readString();
+ local vis4 = packet.readUInt8();
+ setPlayerVisual(player, vis1, vis2, vis3, vis4);
+ }else if(packet_id == packets.selected_class){
+ sendMessageToPlayer(player, 200, 200, 200, LOGIN_MESSAGE);
+ spawnPlayer(player);
+ Players[player].logged = 1;
+ }
+});
+
+addEventHandler("onInit", function(){
+ local myfile = io.file("database/time.log", "r");
+ if(myfile.isOpen){
+ local _hour = myfile.read(io_type.LINE).tointeger();
+ local _min = myfile.read(io_type.LINE).tointeger();
+ setTime(_hour, _min);
+
+ myfile.close();
+ }
+
+ setTimer(function(){
+ setTime(0, 0);
+ }, 5000, 0);
+});
+
+addEventHandler("onPlayerJoin", function(player){
+ packet.reset();
+ packet.writeUInt8(packets.player_info);
+ packet.writeString(getPlayerSerial(player));
+ packet.writeString(getPlayerIP(player));
+ packet.writeString(getPlayerMacAddr(player));
+ packet.send(player, RELIABLE);
+});
+
+addEventHandler("onPlayerRespawn", function(player){
+ if(Players[player].logged == 1){
+ spawnPlayer(player);
+ local cid = Players[player].klasa;
+ local spawnclass = classes[cid].spawn;
+ classes[cid].func(player);
+ setPlayerPosition(player, spawnclass.x, spawnclass.y, spawnclass.z);
+ }
+});
+
+addEventHandler("onExit", function(){
+ local myfile = io.file("database/time.log", "w");
+ if(myfile.isOpen){
+ myfile.write(getTime().hour + "\n");
+ myfile.write(getTime().min + "\n");
+
+ myfile.close();
+ }
+});
diff --git a/gamemode/shared/anims.nut b/gamemode/shared/anims.nut
new file mode 100644
index 0000000..9020e5e
--- /dev/null
+++ b/gamemode/shared/anims.nut
@@ -0,0 +1,318 @@
+anims <- [
+ {
+ name = "Siadanie",
+ inst = "T_STAND_2_SIT"
+ },
+ {
+ name = "Rozglądanie",
+ inst = "T_SEARCH"
+ },
+ {
+ name = "Spanie",
+ inst = "T_STAND_2_SLEEPGROUND"
+ },
+ {
+ name = "Założone ręce",
+ inst = "S_LGUARD"
+ },
+ {
+ name = "Ręce na biodrach",
+ inst = "S_HGUARD"
+ },
+ {
+ name = "Sikanie",
+ inst = "T_STAND_2_PEE"
+ },
+ {
+ name = "Trening",
+ inst = "T_1HSFREE"
+ },
+ {
+ name = "Oglądanie broni",
+ inst = "T_1HSINSPECT"
+ },
+ {
+ name = "Modlitwa",
+ inst = "S_PRAY"
+ },
+ {
+ name = "Plądrowanie",
+ inst = "T_PLUNDER"
+ },
+ {
+ name = "Śmierć (brzuch)",
+ inst = "S_DEAD"
+ },
+ {
+ name = "Śmierć (plecy)",
+ inst = "T_DEADB"
+ },
+ {
+ name = "Dobijanie",
+ inst = "T_1HSFINISH"
+ },
+ {
+ name = "Mycie",
+ inst = "S_WASH"
+ },
+ {
+ name = "Potrząsanie nogami",
+ inst = "R_LEGSHAKE"
+ },
+ {
+ name = "Drapanie po jajach",
+ inst = "R_SCRATCHEGG"
+ },
+ {
+ name = "Drapanie po głowie",
+ inst = "R_SCRATCHHEAD"
+ },
+ {
+ name = "Drapanie po ramieniu",
+ inst = "R_SCRATCHSHOULDER"
+ },
+ {
+ name = "Znudzone kopnięcie",
+ inst = "T_BORINGKICK"
+ },
+ {
+ name = "Pozdrowienie",
+ inst = "T_COMEOVERHERE"
+ },
+ {
+ name = "Dopingowanie",
+ inst = "S_WATCHFIGHT"
+ },
+ {
+ name = "Wzruszenie ramionami",
+ inst = "T_DONTKNOW"
+ },
+ {
+ name = "Machnięcie ręką",
+ inst = "T_FORGETIT"
+ },
+ {
+ name = "Odpędzanie",
+ inst = "T_GETLOST"
+ },
+ {
+ name = "Groźba",
+ inst = "T_IGETYOU"
+ },
+ {
+ name = "Doping (źle)",
+ inst = "T_WATCHFIGHT_OHNO"
+ },
+ {
+ name = "Doping (dobrze)",
+ inst = "T_WATCHFIGHT_YEAH"
+ },
+ {
+ name = "Panika",
+ inst = "S_FIRE_VICTIM"
+ },
+ {
+ name = "Tortury",
+ inst = "S_SUCKENERGY_VICTIM"
+ },
+ {
+ name = "Czarowanie",
+ inst = "S_SDW_S1"
+ },
+ {
+ name = "Czarowanie 2",
+ inst = "T_PRACTICEMAGIC"
+ },
+ {
+ name = "Czarowanie 3",
+ inst = "T_PRACTICEMAGIC2"
+ },
+ {
+ name = "Czarowanie 4",
+ inst = "T_PRACTICEMAGIC3"
+ },
+ {
+ name = "Czarowanie 5",
+ inst = "T_PRACTICEMAGIC4"
+ },
+ {
+ name = "Taniec",
+ inst = "T_DANCE_01"
+ },
+ {
+ name = "Taniec 2",
+ inst = "T_DANCE_02"
+ },
+ {
+ name = "Taniec 3",
+ inst = "T_DANCE_03"
+ },
+ {
+ name = "Taniec 4",
+ inst = "T_DANCE_04"
+ },
+ {
+ name = "Taniec 5",
+ inst = "T_DANCE_05"
+ },
+ {
+ name = "Taniec 6",
+ inst = "T_DANCE_06"
+ },
+ {
+ name = "Taniec 7",
+ inst = "T_DANCE_07"
+ },
+ {
+ name = "Taniec 8",
+ inst = "T_DANCE_08"
+ },
+ {
+ name = "Taniec 9",
+ inst = "T_DANCE_09"
+ },
+ {
+ name = "t_CanNotTake",
+ inst = "T_CANNOTTAKE"
+ },
+ {
+ name = "Podnoszenie",
+ inst = "T_STAND_2_IGET"
+ },
+ {
+ name = "Podnoszenie 2",
+ inst = "S_IGET"
+ },
+ {
+ name = "Wymiana",
+ inst = "T_TRADEITEM"
+ },
+ {
+ name = "Magia fail",
+ inst = "T_CASTFAIL"
+ },
+ {
+ name = "Panika 2",
+ inst = "S_LIGHTNING_VICTIM"
+ },
+ {
+ name = "Panika 3",
+ inst = "S_FREEZE_VICTIM"
+ },
+ {
+ name = "Panika 4",
+ inst = "S_WHIRLWIND_VICTIM"
+ },
+ {
+ name = "Panika 5",
+ inst = "S_INFLATE_VICTIM"
+ },
+ {
+ name = "Panika 6",
+ inst = "S_SWARM_VICTIM"
+ },
+ {
+ name = "Panika 7A",
+ inst = "S_GREENTENTACLEA_VICTIM"
+ },
+ {
+ name = "Panika 7B",
+ inst = "S_GREENTENTACLEB_VICTIM"
+ },
+ {
+ name = "Panika 7C",
+ inst = "S_GREENTENTACLEC_VICTIM"
+ },
+ {
+ name = "Panika 8A",
+ inst = "S_FEAR_VICTIM"
+ },
+ {
+ name = "Panika 8B",
+ inst = "S_FEAR_VICTIM2"
+ },
+ {
+ name = "Panika 8C",
+ inst = "S_FEAR_VICTIM3"
+ },
+ {
+ name = "Panika 9",
+ inst = "S_VICTIM_SLE"
+ },
+ {
+ name = "Papier",
+ inst = "S_MAP_S0"
+ },
+ {
+ name = "Papier 2",
+ inst = "S_MAPSEALED_S0"
+ },
+ {
+ name = "Plucie ogniem",
+ inst = "S_FIRESPIT_S0"
+ },
+ {
+ name = "Klęczenie",
+ inst = "T_CHESTSMALL_S0_2_STAND"
+ },
+ {
+ name = "Modlitwa 2",
+ inst = "T_IDOL_S0_2_STAND"
+ },
+ {
+ name = "Naprawianie",
+ inst = "S_REPAIR_S0"
+ },
+ {
+ name = "s_innos_s0",
+ inst = "S_INNOS_S0"
+ },
+ {
+ name = "Skarb",
+ inst = "S_TREASURE_S0_2_S1"
+ },
+ {
+ name = "Salut",
+ inst = "S_HGUARD_GREET"
+ },
+ {
+ name = "Zakaz",
+ inst = "S_HGUARD_NOENTRY"
+ },
+ {
+ name = "Pozwolenie",
+ inst = "S_HGUARD_COMEIN"
+ },
+ {
+ name = "Salut 2",
+ inst = "S_LGUARD_GREET"
+ },
+ {
+ name = "Zakaz 2",
+ inst = "S_LGUARD_NOENTRY"
+ },
+ {
+ name = "Pozwolenie 2",
+ inst = "S_LGUARD_COMEIN"
+ },
+ {
+ name = "t_lguard_allright",
+ inst = "S_LGUARD_ALLRIGHT"
+ },
+ {
+ name = "zmiana nogi",
+ inst = "T_LGUARD_CHANGELEG"
+ },
+ {
+ name = "Powitanie",
+ inst = "T_GREETGRD"
+ },
+ {
+ name = "Powitanie 2",
+ inst = "T_GREETNOV"
+ },
+ {
+ name = "rytuał",
+ inst = "T_LEAN_2_STAND"
+ }
+];
diff --git a/gamemode/shared/class.nut b/gamemode/shared/class.nut
new file mode 100644
index 0000000..6d5d779
--- /dev/null
+++ b/gamemode/shared/class.nut
@@ -0,0 +1,460 @@
+classes <- [
+ {
+ name = "Knecht",
+ guild = "Ludzie",
+ description = "...",
+ spawn = [-10294.9, -14.5313, -12431.5, 116.979],
+ func = function(id) {
+ setPlayerInstance(id, "PC_HERO");
+ setPlayerHealth(id, 100);
+ setPlayerMaxHealth(id, 100);
+ setPlayerMana(id, 10);
+ setPlayerMaxMana(id, 10);
+ setPlayerStrength(id, 30);
+ setPlayerDexterity(id, 30);
+ setPlayerSkillWeapon(id, WEAPON_1H, 20);
+ setPlayerSkillWeapon(id, WEAPON_2H, 20);
+ setPlayerSkillWeapon(id, WEAPON_BOW, 20);
+ setPlayerSkillWeapon(id, WEAPON_CBOW, 20);
+ setPlayerTalent(id, 0, 1);
+ equipArmor(id, Items.id("ITAR_MIL_L"));
+ equipMeleeWeapon(id, Items.id("ITMW_1H_VLK_SWORD"));
+ equipRangedWeapon(id, Items.id("ITRW_CROSSBOW_L_01"));
+ giveItem(id, Items.id("ITRW_BOLT"), 50);
+ //applyPlayerOverlay(id, Mds.id("HUMANS_MILITIA.MDS"));
+ }
+ },
+ {
+ name = "Żołnierz",
+ guild = "Ludzie",
+ description = "...",
+ spawn = [-9339.45, -14.8438, -14685, 294.52],
+ func = function(id) {
+ setPlayerInstance(id, "PC_HERO");
+ setPlayerHealth(id, 150);
+ setPlayerMaxHealth(id, 150);
+ setPlayerMana(id, 10);
+ setPlayerMaxMana(id, 10);
+ setPlayerStrength(id, 50);
+ setPlayerDexterity(id, 50);
+ setPlayerSkillWeapon(id, WEAPON_1H, 30);
+ setPlayerSkillWeapon(id, WEAPON_2H, 30);
+ setPlayerSkillWeapon(id, WEAPON_BOW, 30);
+ setPlayerSkillWeapon(id, WEAPON_CBOW, 30);
+ setPlayerTalent(id, 0, 1);
+ equipArmor(id, Items.id("ITAR_MIL_M"));
+ equipMeleeWeapon(id, Items.id("ITMW_SHORTSWORD5"));
+ equipRangedWeapon(id, Items.id("ITRW_MIL_CROSSBOW"));
+ giveItem(id, Items.id("ITRW_BOLT"), 50);
+ //applyPlayerOverlay(id, Mds.id("HUMANS_MILITIA.MDS"));
+ }
+ },
+ {
+ name = "Mag Ognia",
+ guild = "Ludzie",
+ description = "...",
+ spawn = [-9472.66, -14.7656, -17306.6, 141.935],
+ func = function(id) {
+ setPlayerInstance(id, "PC_HERO");
+ setPlayerHealth(id, 300);
+ setPlayerMaxHealth(id, 300);
+ setPlayerMana(id, 100);
+ setPlayerMaxMana(id, 100);
+ setPlayerStrength(id, 80);
+ setPlayerDexterity(id, 80);
+ setPlayerSkillWeapon(id, WEAPON_1H, 50);
+ setPlayerSkillWeapon(id, WEAPON_2H, 50);
+ setPlayerSkillWeapon(id, WEAPON_BOW, 50);
+ setPlayerSkillWeapon(id, WEAPON_CBOW, 50);
+ setPlayerTalent(id, 0, 1);
+ setPlayerMagicLevel(id, 6);
+ equipArmor(id, Items.id("ITAR_KDF_H"));
+ equipMeleeWeapon(id, Items.id("ITMW_ADDON_STAB05"));
+ //applyPlayerOverlay(id, Mds.id("HUMANS_MILITIA.MDS"));
+ }
+ },
+ {
+ name = "Rycerz",
+ guild = "Ludzie",
+ description = "...",
+ spawn = [-9579.22, 560.938, -12588.4, 212.693],
+ func = function(id) {
+ setPlayerInstance(id, "PC_HERO");
+ setPlayerHealth(id, 300);
+ setPlayerMaxHealth(id, 300);
+ setPlayerMana(id, 75);
+ setPlayerMaxMana(id, 75);
+ setPlayerStrength(id, 100);
+ setPlayerDexterity(id, 100);
+ setPlayerSkillWeapon(id, WEAPON_1H, 70);
+ setPlayerSkillWeapon(id, WEAPON_2H, 70);
+ setPlayerSkillWeapon(id, WEAPON_BOW, 70);
+ setPlayerSkillWeapon(id, WEAPON_CBOW, 70);
+ setPlayerTalent(id, 0, 1);
+ equipArmor(id, Items.id("ITAR_PAL_M"));
+ equipMeleeWeapon(id, Items.id("ITMW_2H_PAL_SWORD"));
+ //applyPlayerOverlay(id, Mds.id("HUMANS_MILITIA.MDS"));
+ }
+ },
+ {
+ name = "Paladyn",
+ guild = "Ludzie",
+ description = "...",
+ spawn = [-9515.08, 490.625, -16375, 278.035],
+ serial = ["60c5ac7101bcb18ad14d6f90de0838814bd261a"],
+ func = function(id) {
+ setPlayerInstance(id, "PC_HERO");
+ setPlayerHealth(id, 500);
+ setPlayerMaxHealth(id, 500);
+ setPlayerMana(id, 100);
+ setPlayerMaxMana(id, 100);
+ setPlayerStrength(id, 120);
+ setPlayerDexterity(id, 120);
+ setPlayerSkillWeapon(id, WEAPON_1H, 100);
+ setPlayerSkillWeapon(id, WEAPON_2H, 100);
+ setPlayerSkillWeapon(id, WEAPON_BOW, 100);
+ setPlayerSkillWeapon(id, WEAPON_CBOW, 100);
+ setPlayerTalent(id, 0, 1);
+ equipArmor(id, Items.id("ITAR_PAL_H"));
+ equipMeleeWeapon(id, Items.id("ITMW_2H_BLESSED_02"));
+ //applyPlayerOverlay(id, Mds.id("HUMANS_MILITIA.MDS"));
+ }
+ },
+//
+ {
+ name = "Ork Zwiadowca",
+ guild = "Orkowie",
+ description = "...",
+ spawn = [-18909.5, 2094.61, 14631.3, 290.703],
+ func = function(id) {
+ setPlayerInstance(id, "ORCWARRIOR_HARAD");
+ setPlayerHealth(id, 100);
+ setPlayerMaxHealth(id, 100);
+ setPlayerMana(id, 10);
+ setPlayerMaxMana(id, 10);
+ setPlayerStrength(id, 30);
+ setPlayerDexterity(id, 30);
+ setPlayerSkillWeapon(id, WEAPON_1H, 20);
+ setPlayerSkillWeapon(id, WEAPON_2H, 20);
+ setPlayerSkillWeapon(id, WEAPON_BOW, 20);
+ setPlayerSkillWeapon(id, WEAPON_CBOW, 20);
+ setPlayerTalent(id, 0, 1);
+ //equipMeleeWeapon(id, Items.id("ITMW_1H_VLK_SWORD"));
+ equipRangedWeapon(id, Items.id("ITRW_CROSSBOW_L_1"));
+ giveItem(id, Items.id("ITRW_BOLT"), 50);
+ //applyPlayerOverlay(id, Mds.id("HUMANS_RELAXED.MDS"));
+ }
+ },
+ {
+ name = "Orkowy Żołnierz",
+ guild = "Orkowie",
+ description = "...",
+ spawn = [-18909.5, 2094.61, 14631.3, 290.703],
+ func = function(id) {
+ setPlayerInstance(id, "ORCWARRIOR_ROAM");
+ setPlayerHealth(id, 150);
+ setPlayerMaxHealth(id, 150);
+ setPlayerMana(id, 10);
+ setPlayerMaxMana(id, 10);
+ setPlayerStrength(id, 50);
+ setPlayerDexterity(id, 50);
+ setPlayerSkillWeapon(id, WEAPON_1H, 30);
+ setPlayerSkillWeapon(id, WEAPON_2H, 30);
+ setPlayerSkillWeapon(id, WEAPON_BOW, 30);
+ setPlayerSkillWeapon(id, WEAPON_CBOW, 30);
+ setPlayerTalent(id, 0, 1);
+ //equipMeleeWeapon(id, Items.id("ITMW_SHORTSWORD5"));
+ equipRangedWeapon(id, Items.id("ITRW_MIL_CROSSBOW"));
+ giveItem(id, Items.id("ITRW_BOLT"), 50);
+ //applyPlayerOverlay(id, Mds.id("HUMANS_RELAXED.MDS"));
+ }
+ },
+ {
+ name = "Orkowy Szaman",
+ guild = "Orkowie",
+ description = "...",
+ spawn = [-14777, 2207.73, 20490.5, 285.88],
+ func = function(id) {
+ setPlayerInstance(id, "ORCSHAMAN_SIT");
+ setPlayerHealth(id, 300);
+ setPlayerMaxHealth(id, 300);
+ setPlayerMana(id, 100);
+ setPlayerMaxMana(id, 100);
+ setPlayerStrength(id, 80);
+ setPlayerDexterity(id, 80);
+ setPlayerSkillWeapon(id, WEAPON_1H, 50);
+ setPlayerSkillWeapon(id, WEAPON_2H, 50);
+ setPlayerSkillWeapon(id, WEAPON_BOW, 50);
+ setPlayerSkillWeapon(id, WEAPON_CBOW, 50);
+ setPlayerTalent(id, 0, 1);
+ setPlayerMagicLevel(id, 6);
+ //equipMeleeWeapon(id, Items.id("ITMW_SCHWERT1"));
+ //applyPlayerOverlay(id, Mds.id("HUMANS_RELAXED.MDS"));
+ }
+ },
+ {
+ name = "Elitarny Orkowy Wojownik",
+ guild = "Orkowie",
+ description = "...",
+ spawn = [-15199.5, 2627.73, 23170, 267.439],
+ func = function(id) {
+ setPlayerInstance(id, "ORCELITE_ROAM");
+ setPlayerHealth(id, 300);
+ setPlayerMaxHealth(id, 300);
+ setPlayerMana(id, 75);
+ setPlayerMaxMana(id, 75);
+ setPlayerStrength(id, 100);
+ setPlayerDexterity(id, 100);
+ setPlayerSkillWeapon(id, WEAPON_1H, 70);
+ setPlayerSkillWeapon(id, WEAPON_2H, 70);
+ setPlayerSkillWeapon(id, WEAPON_BOW, 70);
+ setPlayerSkillWeapon(id, WEAPON_CBOW, 70);
+ setPlayerTalent(id, 0, 1);
+ //equipMeleeWeapon(id, Items.id("ITMW_STREITAXT1"));
+ //applyPlayerOverlay(id, Mds.id("HUMANS_RELAXED.MDS"));
+ }
+ },
+ {
+ name = "Orkowy Generał",
+ guild = "Orkowie",
+ description = "...",
+ spawn = [-20038.7, 2207.66, 20490.5, 77.8558],
+ serial = ["60c5ac7101bcb18ad14d6f90de0838814bd261a"],
+ func = function(id) {
+ setPlayerInstance(id, "ORCELITE_ANTIPALADIN");
+ setPlayerHealth(id, 500);
+ setPlayerMaxHealth(id, 500);
+ setPlayerMana(id, 100);
+ setPlayerMaxMana(id, 100);
+ setPlayerStrength(id, 120);
+ setPlayerDexterity(id, 120);
+ setPlayerSkillWeapon(id, WEAPON_1H, 100);
+ setPlayerSkillWeapon(id, WEAPON_2H, 100);
+ setPlayerSkillWeapon(id, WEAPON_BOW, 100);
+ setPlayerSkillWeapon(id, WEAPON_CBOW, 100);
+ setPlayerTalent(id, 0, 1);
+ //equipMeleeWeapon(id, Items.id("ITMW_2H_SPECIAL_02"));
+ //applyPlayerOverlay(id, Mds.id("HUMANS_RELAXED.MDS"));
+ }
+ },
+//
+ {
+ name = "Łowca Smoków",
+ guild = "VIP",
+ description = "...",
+ spawn = [-23257.2, 1566.56, -4629.22, 109.382],
+ serial = ["60c5ac7101bcb18ad14d6f90de0838814bd261a"],
+ func = function(id) {
+ setPlayerInstance(id, "PC_HERO");
+ setPlayerHealth(id, 400);
+ setPlayerMaxHealth(id, 400);
+ setPlayerMana(id, 75);
+ setPlayerMaxMana(id, 75);
+ setPlayerStrength(id, 100);
+ setPlayerDexterity(id, 100);
+ setPlayerSkillWeapon(id, WEAPON_1H, 100);
+ setPlayerSkillWeapon(id, WEAPON_2H, 100);
+ setPlayerSkillWeapon(id, WEAPON_BOW, 100);
+ setPlayerSkillWeapon(id, WEAPON_CBOW, 100);
+ setPlayerTalent(id, 0, 1);
+ equipArmor(id, Items.id("ITAR_DJG_M"));
+ equipMeleeWeapon(id, Items.id("ITMW_RUBINKLINGE"));
+ //applyPlayerOverlay(id, Mds.id("HUMANS_MILITIA.MDS"));
+ }
+ },
+ {
+ name = "Najemnik Orków",
+ guild = "VIP",
+ description = "...",
+ spawn = [-17389.1, 2094.69, 15068.3, 254.453],
+ serial = ["60c5ac7101bcb18ad14d6f90de0838814bd261a"],
+ func = function(id) {
+ setPlayerInstance(id, "PC_HERO");
+ setPlayerHealth(id, 400);
+ setPlayerMaxHealth(id, 400);
+ setPlayerMana(id, 75);
+ setPlayerMaxMana(id, 75);
+ setPlayerStrength(id, 100);
+ setPlayerDexterity(id, 100);
+ setPlayerSkillWeapon(id, WEAPON_1H, 100);
+ setPlayerSkillWeapon(id, WEAPON_2H, 100);
+ setPlayerSkillWeapon(id, WEAPON_BOW, 100);
+ setPlayerSkillWeapon(id, WEAPON_CBOW, 100);
+ setPlayerTalent(id, 0, 1);
+ equipArmor(id, Items.id("ITAR_RAVEN_ADDON"));
+ equipMeleeWeapon(id, Items.id("ITMW_RUBINKLINGE"));
+ //applyPlayerOverlay(id, Mds.id("HUMANS_MILITIA.MDS"));
+ }
+ },
+ {
+ name = "Jaszczuroczłek",
+ guild = "VIP",
+ description = "...",
+ spawn = [-20176.1, 2094.61, 15237.9, 241.45],
+ serial = ["60c5ac7101bcb18ad14d6f90de0838814bd261a"],
+ func = function(id) {
+ setPlayerInstance(id, "DRACONIAN");
+ setPlayerHealth(id, 400);
+ setPlayerMaxHealth(id, 400);
+ setPlayerMana(id, 75);
+ setPlayerMaxMana(id, 75);
+ setPlayerStrength(id, 100);
+ setPlayerDexterity(id, 100);
+ setPlayerSkillWeapon(id, WEAPON_1H, 100);
+ setPlayerSkillWeapon(id, WEAPON_2H, 100);
+ setPlayerSkillWeapon(id, WEAPON_BOW, 100);
+ setPlayerSkillWeapon(id, WEAPON_CBOW, 100);
+ setPlayerTalent(id, 0, 1);
+ //equipMeleeWeapon(id, Items.id("ITMW_RUBINKLINGE"));
+ //applyPlayerOverlay(id, Mds.id("HUMANS_MILITIA.MDS"));
+ }
+ },
+ {
+ name = "Mag Wody",
+ guild = "VIP",
+ description = "...",
+ spawn = [-21066.1, 1496.33, -3869.69, 242.95],
+ serial = ["b1fc75842d3778c0981fc0dc857e46901b64bd5",
+ "50d78fc177c4a7764b40795c6393a237cc78a0e",
+ "60c5ac7101bcb18ad14d6f90de0838814bd261a"],
+ func = function(id) {
+ setPlayerInstance(id, "PC_HERO");
+ setPlayerHealth(id, 400);
+ setPlayerMaxHealth(id, 400);
+ setPlayerMana(id, 100);
+ setPlayerMaxMana(id, 100);
+ setPlayerStrength(id, 100);
+ setPlayerDexterity(id, 100);
+ setPlayerSkillWeapon(id, WEAPON_1H, 100);
+ setPlayerSkillWeapon(id, WEAPON_2H, 100);
+ setPlayerSkillWeapon(id, WEAPON_BOW, 100);
+ setPlayerSkillWeapon(id, WEAPON_CBOW, 100);
+ setPlayerTalent(id, 0, 1);
+ setPlayerMagicLevel(id, 6);
+ equipArmor(id, Items.id("ITAR_KDW_H"));
+ equipMeleeWeapon(id, Items.id("ITMW_ADDON_STAB05"));
+ //applyPlayerOverlay(id, Mds.id("HUMANS_MAGE.MDS"));
+ }
+ },
+ {
+ name = "Nekromanta",
+ guild = "VIP",
+ description = "...",
+ spawn = [-17351.3, 2357.73, 17654.8, 354.095],
+ serial = ["60c5ac7101bcb18ad14d6f90de0838814bd261a"],
+ func = function(id) {
+ setPlayerInstance(id, "PC_HERO");
+ setPlayerHealth(id, 400);
+ setPlayerMaxHealth(id, 400);
+ setPlayerMana(id, 100);
+ setPlayerMaxMana(id, 100);
+ setPlayerStrength(id, 100);
+ setPlayerDexterity(id, 100);
+ setPlayerSkillWeapon(id, WEAPON_1H, 100);
+ setPlayerSkillWeapon(id, WEAPON_2H, 100);
+ setPlayerSkillWeapon(id, WEAPON_BOW, 100);
+ setPlayerSkillWeapon(id, WEAPON_CBOW, 100);
+ setPlayerTalent(id, 0, 1);
+ setPlayerMagicLevel(id, 6);
+ equipArmor(id, Items.id("ITAR_XARDAS"));
+ equipMeleeWeapon(id, Items.id("ITMW_ADDON_STAB05"));
+ //applyPlayerOverlay(id, Mds.id("HUMANS_MAGE.MDS"));
+ }
+ },
+ {
+ name = "Upadły Paladyn",
+ guild = "VIP",
+ description = "...",
+ spawn = [-20336.6, 2407.73, 17546, 90.4353],
+ serial = ["60c5ac7101bcb18ad14d6f90de0838814bd261a"],
+ func = function(id) {
+ setPlayerInstance(id, "SKELETON_LORD");
+ setPlayerHealth(id, 400);
+ setPlayerMaxHealth(id, 400);
+ setPlayerMana(id, 75);
+ setPlayerMaxMana(id, 75);
+ setPlayerStrength(id, 100);
+ setPlayerDexterity(id, 100);
+ setPlayerSkillWeapon(id, WEAPON_1H, 100);
+ setPlayerSkillWeapon(id, WEAPON_2H, 100);
+ setPlayerSkillWeapon(id, WEAPON_BOW, 100);
+ setPlayerSkillWeapon(id, WEAPON_CBOW, 100);
+ setPlayerTalent(id, 0, 1);
+ equipArmor(id, Items.id("ITAR_PAL_SKEL"));
+ equipMeleeWeapon(id, Items.id("ITMW_ZWEIHAENDER1"));
+ //applyPlayerOverlay(id, Mds.id("HUMANS_MILITIA.MDS"));
+ }
+ },
+ {
+ name = "Ork Ożywieniec",
+ guild = "VIP",
+ description = "...",
+ spawn = [-20078.5, 2627.73, 23445.6, 108.08],
+ serial = ["60c5ac7101bcb18ad14d6f90de0838814bd261a"],
+ func = function(id) {
+ setPlayerInstance(id, "UNDEADORCWARRIOR");
+ setPlayerHealth(id, 400);
+ setPlayerMaxHealth(id, 400);
+ setPlayerMana(id, 100);
+ setPlayerMaxMana(id, 100);
+ setPlayerStrength(id, 100);
+ setPlayerDexterity(id, 100);
+ setPlayerSkillWeapon(id, WEAPON_1H, 100);
+ setPlayerSkillWeapon(id, WEAPON_2H, 100);
+ setPlayerSkillWeapon(id, WEAPON_BOW, 100);
+ setPlayerSkillWeapon(id, WEAPON_CBOW, 100);
+ setPlayerTalent(id, 0, 1);
+ equipMeleeWeapon(id, Items.id("ITMW_ZWEIHAENDER1"));
+ //applyPlayerOverlay(id, Mds.id("HUMANS_MILITIA.MDS"));
+ }
+ },
+//
+ {
+ name = "Arkhan Qualshy",
+ guild = "Klasa Prywatna",
+ description = "Podróżnik, który zwiedza każdy zakamarek świata.",
+ spawn = [-22886.3, 1420, -857.5, 133.096],
+ serial = ["60c5ac7101bcb18ad14d6f90de0838814bd261a"],
+ func = function(id) {
+ setPlayerInstance(id, "PC_HERO");
+ setPlayerHealth(id, 400);
+ setPlayerMaxHealth(id, 400);
+ setPlayerMana(id, 75);
+ setPlayerMaxMana(id, 75);
+ setPlayerStrength(id, 100);
+ setPlayerDexterity(id, 100);
+ setPlayerSkillWeapon(id, WEAPON_1H, 100);
+ setPlayerSkillWeapon(id, WEAPON_2H, 100);
+ setPlayerSkillWeapon(id, WEAPON_BOW, 100);
+ setPlayerSkillWeapon(id, WEAPON_CBOW, 100);
+ setPlayerTalent(id, 0, 1);
+ equipArmor(id, Items.id("ITAR_RANGER_ADDON"));
+ equipMeleeWeapon(id, Items.id("ITMW_1H_SPECIAL_02"));
+ //applyPlayerOverlay(id, Mds.id("HUMANS_MILITIA.MDS"));
+ }
+ },
+ {
+ name = "Spazzmaticus",
+ guild = "Klasa Prywatna",
+ description = "Ten drań nie ma nawet złota!",
+ spawn = [-22886.3, 1420, -857.5, 133.096],
+ serial = ["3e8fdeba74409ee806a3e750ae3649e4f454920"],
+ func = function(id) {
+ setPlayerInstance(id, "PC_HERO");
+ setPlayerHealth(id, 400);
+ setPlayerMaxHealth(id, 400);
+ setPlayerMana(id, 75);
+ setPlayerMaxMana(id, 75);
+ setPlayerStrength(id, 100);
+ setPlayerDexterity(id, 100);
+ setPlayerSkillWeapon(id, WEAPON_1H, 100);
+ setPlayerSkillWeapon(id, WEAPON_2H, 100);
+ setPlayerSkillWeapon(id, WEAPON_BOW, 100);
+ setPlayerSkillWeapon(id, WEAPON_CBOW, 100);
+ setPlayerTalent(id, 0, 1);
+ equipArmor(id, Items.id("ITAR_RANGER_ADDON"));
+ equipMeleeWeapon(id, Items.id("ITMW_2H_SPECIAL_01"));
+ //applyPlayerOverlay(id, Mds.id("HUMANS_.MDS"));
+ }
+ }
+];
diff --git a/gamemode/shared/packets.nut b/gamemode/shared/packets.nut
new file mode 100644
index 0000000..cd4bb35
--- /dev/null
+++ b/gamemode/shared/packets.nut
@@ -0,0 +1,15 @@
+packet <- Packet();
+
+enum packets {
+ player_info,
+ select_class,
+ selected_class,
+ change_class,
+ visual,
+ first_join,
+ next_join,
+ checklog,
+ logged,
+ logfail,
+ size
+};
diff --git a/gamemode/shared/text.nut b/gamemode/shared/text.nut
new file mode 100644
index 0000000..5734300
--- /dev/null
+++ b/gamemode/shared/text.nut
@@ -0,0 +1,119 @@
+// CLIENT //
+ // GUI //
+GUI_LOGO <- "Irdorath RP";
+GUI_GTIME <- "Czas w grze ";
+GUI_RTIME <- "Czas realny ";
+GUI_CHARA <- "Postać";
+GUI_EXIT <- "Wyjście z gry";
+
+GUI_LOGIN <- "Logowanie";
+GUI_TEXTLOG <- "Login";
+GUI_TEXTPAS <- "Hasło";
+
+ // MAIN //
+MAIN_CSELECT <- "Użyj A i D do wyboru klasy.";
+
+ // VISUAL //
+VIS_HEADER <- "Wygląd";
+VIS_HMODEL <- "Model Głowy";
+VIS_HTEX <- "Tekstura Głowy";
+VIS_BMODEL <- "Model Ciała";
+VIS_BTEX <- "Tekstura Ciała";
+VIS_EXIT <- "Wyjście";
+
+// SERVER //
+ // ACP //
+ACP_ERROR <- "(PANEL) Nie możesz wpływać na niepodłączonych lub niezalogowanych graczy!";
+ACP_ERROR2 <- "(PANEL) Nie rozpoznano komendy!";
+ACP_HELP <- "-=========== ACP ===========- \n"
+ + "/color id r g b - Zmiana koloru gracza \n"
+ + "/name id nick - Zmiana nicku gracza \n"
+ + "/kick id powod - Wyrzucenie gracza \n"
+ + "/ban id minuty powod - Ban gracza (brak czasu = na zawsze) \n"
+ + "/tp from_id to_id - Teleportacja gracza do gracza \n"
+ + "/giveitem id kod - Dodanie przedmiotu do ekwipunku \n"
+ + "/time godzina minuta - Zmiana czasu serwera \n"
+ + "/scale id x y z - Zmiana skali gracza \n"
+ + "/pos nazwa - Stworzenie pozycji \n"
+ + "/awans id klasa - Zmiana klasy gracza \n"
+ + "/g - Czat globalny OOC \n"
+ + "/p - Czat globalny IC \n"
+ + "/apw - Czat administracyjny/report\n"
+ + "/gpw - Czat gildyjny \n"
+ + "/listaklas - Lista wszystkich klas \n"
+ + "-=========== ACP ===========-";
+ACP_LOGHELP <- " wywołał menu ACP.";
+
+ACP_PARCOLOR <- "(PANEL) /color id r g b";
+ACP_MSGCOLOR <- "(PANEL) Nowy kolor: ";
+ACP_LOGCOLOR <- " zmienił kolor ";
+
+ACP_PARNAME <- "(PANEL) /name id nickname";
+ACP_MSGNAME <- "(PANEL) Nowy nick: ";
+ACP_LOGNAME <- " zmienił nick "
+
+ACP_PARKICK <- "(PANEL) /kick id reason";
+ACP_MSGKICK <- "(PANEL) Wyrzucono: ";
+ACP_LOGKICK <- " wyrzucił ";
+
+ACP_PARKICKALL <- "(PANEL) /kickall reason";
+//ACP_MSGKICKALL <-
+ACP_LOGKICKALL <- " wyrzucił wszystkich graczy za: ";
+
+ACP_PARBAN <- "(PANEL) /ban id minutes reason";
+ACP_MSGBAN <- "(PANEL) Zbanowano: ";
+ACP_LOGBAN <- " zbanował ";
+
+ACP_PARTP <- "(PANEL) /tp from_id to_id";
+ACP_ERRORTP <- "(PANEL) Nie możesz teleportować tego samego gracza do siebie!";
+ACP_MSGTP <- "(PANEL) Teleportowałeś ";
+ACP_LOGTP <- " teleportował ";
+
+ACP_PARTPALL <- "(PANEL) /tpall to_id";
+ACP_MSGTPALL <- "(PANEL) Teleportowano wszystkich do ";
+ACP_LOGTPALL <- " teleportował wszystkich do ";
+
+ACP_PARGIVE <- "(PANEL) /giveitem id instance amount";
+ACP_MSGGIVE <- "(PANEL) Nowy przedmiot: ";
+ACP_LOGGIVE <- " dał ";
+
+ACP_PARTIME <- "(PANEL) /time hour min";
+ACP_MSGTIME <- "(PANEL) Nowy czas: ";
+ACP_LOGTIME <- " zmienił czas na ";
+
+ACP_PARSCALE <- "(PANEL) /scale id x y z";
+ACP_MSGSCALE <- "(PANEL) Nowa skala: ";
+ACP_LOGSCALE <- " zmienił skalę ";
+
+ACP_PARPOS <- "(PANEL) /pos nazwa";
+ACP_MSGPOS <- "(PANEL) Zapisałeś pozycję o nazwie ";
+//ACP_LOGPOS <-
+
+ACP_PARPROMO <- "(PANEL) /awans id class";
+ACP_MSGPROMO <- "(PANEL) Nowa klasa: ";
+ACP_LOGPROMO <- " zmienił klasę ";
+
+//ACP_PARLIST <-
+//ACP_MSGLIST <-
+ACP_LOGLIST <- " wywołał menu klas";
+
+ // CHAT //
+CHAT_SCREAM <- " krzyczy ";
+CHAT_DISTANCESCREAM <- "Ktoś krzyczy ";
+CHAT_WHISPER <- " szepcze ";
+CHAT_DISTANCEWHISPER <- "Ktoś szepcze ";
+CHAT_SPEAK <- " mówi ";
+CHAT_DISTANCESPEAK <- "Ktoś mówi ";
+
+ // LOGIN //
+LOGIN_KICK <- "Zalecamy zmianę nicku w launcherze Gothic 2 Online.";
+LOGIN_JOIN <- " dołączył do gry.";
+LOGIN_LEAVE <- " wyszedł z gry.";
+LOGIN_LOGGED <- " zalogował się.";
+LOGIN_REGISTERED <- " zarejestrował się.";
+LOGIN_FAIL <- "Wprowadzone dane są nieprawidłowe.";
+LOGIN_MESSAGE <- "Wygląd postaci zmienisz pod przyciskiem F8. \n"
+ + "Menu animacji znajduje się pod przyciskiem F10.";
+
+ // LOGIN //
+EXIT_KICK <- "Niekonwencjonalne wyjście z serwera."
diff --git a/lib/file.nut b/lib/file.nut
new file mode 100644
index 0000000..1eb6fe0
--- /dev/null
+++ b/lib/file.nut
@@ -0,0 +1,140 @@
+/*
+ -= Extended file class =-
+ Author: Bimbol
+
+ //-------------------------------------------
+
+ USING EXAMPLE:
+
+ //-------------------------------------------
+ // Writing string to file
+ //-------------------------------------------
+
+ local myfile = io.file("test.txt", "w");
+ if (myfile.isOpen)
+ {
+ myfile.write("Test :)");
+ myfile.write("And this is test2\n");
+ myfile.write("Gothic 2 Online");
+ myfile.close();
+ }
+ else
+ print(myfile.errorMsg)
+
+ //-------------------------------------------
+ // Reading string from file
+ //-------------------------------------------
+
+ local myfile = io.file("test.txt", "r");
+ if (myfile.isOpen)
+ {
+ print(myfile.read(io_type.ALL));
+ myfile.seek(0);
+
+ print("1 Line:");
+ print(myfile.read(io_type.LINE));
+
+ print("2 Line:");
+ print(myfile.read(io_type.LINE));
+
+ print("3 Line:");
+ print(myfile.read(io_type.LINE));
+
+ myfile.close();
+ }
+ else
+ print(myfile.errorMsg);
+
+ //-------------------------------------------
+*/
+
+io <- {}
+
+enum io_type
+{
+ LINE,
+ ALL
+};
+
+class io.file extends file
+{
+ constructor(fileName, mode)
+ {
+ errorMsg = null;
+
+ try
+ {
+ base.constructor(fileName, mode);
+ isOpen = true;
+ }
+ catch (msg)
+ {
+ errorMsg = msg;
+ isOpen = false;
+ }
+ }
+
+ function write(text)
+ {
+ foreach (char in text)
+ {
+ writen(char, 'b');
+ }
+ }
+
+ function read(type = io_type.ALL)
+ {
+ if (type == io_type.LINE)
+ {
+ local line = "";
+ local char;
+
+ while (!eos() && (char = readn('b')))
+ {
+ if (char != '\n')
+ line += char.tochar();
+ else
+ return line;
+ }
+
+ return line.len() == 0 ? null : line;
+ }
+ else if (type == io_type.ALL)
+ {
+ local content = "";
+ local char;
+
+ while (!eos() && (char = readn('b')))
+ {
+ content += char.tochar();
+ }
+
+ return content.len() == 0 ? null : content;
+ }
+
+ return null;
+ }
+
+ function close()
+ {
+ base.close();
+ isOpen = false;
+ }
+
+ errorMsg = null;
+ isOpen = false;
+}
+
+function saveLog(file, params)
+{
+ local myfile = io.file("database/logs/" + file, "a+");
+ if (myfile.isOpen)
+ {
+ local datas = date().day + "/" + date().month + " " + date().hour + ":" + date().min;
+ myfile.write(datas + " || " + params + " \n");
+ myfile.close();
+ }
+ else
+ print(myfile.errorMsg)
+};
+//saveLog("nazwapliku.txt", jakikolwiekinput);
diff --git a/lib/gui-framework/abstract/alignment.nut b/lib/gui-framework/abstract/alignment.nut
new file mode 100644
index 0000000..b7eebf8
--- /dev/null
+++ b/lib/gui-framework/abstract/alignment.nut
@@ -0,0 +1,16 @@
+class GUI.Alignment
+{
+#protected:
+ m_alignment = null
+
+#public:
+ function getAlignment()
+ {
+ return m_alignment
+ }
+
+ function setAlignment(alignment)
+ {
+ m_alignment = alignment
+ }
+}
diff --git a/lib/gui-framework/abstract/base.nut b/lib/gui-framework/abstract/base.nut
new file mode 100644
index 0000000..5c84001
--- /dev/null
+++ b/lib/gui-framework/abstract/base.nut
@@ -0,0 +1,255 @@
+addEvent("GUI.onTakeFocus")
+addEvent("GUI.onLostFocus")
+
+addEvent("GUI.onMouseIn")
+addEvent("GUI.onMouseOut")
+
+addEvent("GUI.onMouseMove")
+
+addEvent("GUI.onMouseUp")
+addEvent("GUI.onMouseDown")
+
+local elementPointedByCursor = null
+local focusedElement = null
+
+class GUI.Base
+{
+ static m_objects = []
+
+#protected:
+ m_id = -1
+
+ m_lastButtonPressed = -1
+
+ m_visible = false
+ m_isDisabled = false
+
+#public:
+ toolTip = null
+ parent = null
+
+ constructor()
+ {
+ addToArray()
+ }
+
+ function destroy()
+ {
+ if (elementPointedByCursor == this)
+ elementPointedByCursor = null
+
+ if(focusedElement == this)
+ focusedElement = null
+
+ if (toolTip)
+ {
+ if (toolTip.getToolTip(this))
+ delete toolTip.m_toolTip[this]
+
+ toolTip = null
+ }
+
+ removeFromArray()
+ }
+
+ function addToArray()
+ {
+ m_id = m_objects.len()
+ m_objects.push(this)
+ }
+
+ function removeFromArray()
+ {
+ for (local i = m_objects.len() - 1; i > m_id; --i)
+ --m_objects[i].m_id
+
+ m_objects.remove(m_id)
+ }
+
+ function top()
+ {
+ removeFromArray()
+ addToArray()
+ }
+
+ function getVisible()
+ {
+ return m_visible
+ }
+
+ function setVisible(visible)
+ {
+ if (!visible && this == focusedElement)
+ this.loseFocus()
+
+ m_visible = visible
+ }
+
+ function getDisabled()
+ {
+ return m_isDisabled
+ }
+
+ function setDisabled(disabled)
+ {
+ if (disabled && isFocused())
+ loseFocus()
+
+ m_isDisabled = disabled
+ }
+
+ function checkIsMouseAt()
+ {
+ if (!isCursorVisible())
+ return false
+
+ local texPosition
+ local texSize
+
+ if (base)
+ {
+ texPosition = base.getPositionPx()
+ texSize = base.getSizePx()
+ }
+ else
+ {
+ texPosition = getPositionPx()
+ texSize = getSizePx()
+ }
+
+ local cursorPosition = getCursorPositionPx()
+
+ if (cursorPosition.x >= texPosition.x && cursorPosition.x <= texPosition.x + texSize.width
+ && cursorPosition.y >= texPosition.y && cursorPosition.y <= texPosition.y + texSize.height)
+ return true
+
+ return false
+ }
+
+ function isMouseAt()
+ {
+ return elementPointedByCursor == this
+ }
+
+ function isFocused()
+ {
+ return focusedElement == this
+ }
+
+ function takeFocus()
+ {
+ focusedElement = this
+ callEvent("GUI.onTakeFocus", this)
+ }
+
+ function loseFocus()
+ {
+ local tmpRef = focusedElement
+ focusedElement = null
+
+ callEvent("GUI.onLostFocus", tmpRef)
+ }
+
+ static function getElementPointedByCursor()
+ {
+ return elementPointedByCursor
+ }
+
+ static function getFocusedElement()
+ {
+ return focusedElement
+ }
+
+ static function uncheckElementPointedByCursor()
+ {
+ callEvent("GUI.onMouseOut", elementPointedByCursor)
+ elementPointedByCursor = null
+ }
+
+ static function onRender()
+ {
+ local cursorPosition = getCursorPositionPx()
+ local deltaTime = getFrameTime()
+
+ foreach (object in GUI.Base.m_objects)
+ {
+ if (!object.getVisible())
+ continue
+
+ callEvent("GUI.onRender", object)
+ }
+ }
+
+ static function onMouseMove(newCursorX, newCursorY, oldCursorX, oldCursorY)
+ {
+ if (elementPointedByCursor && !elementPointedByCursor.getVisible())
+ GUI.Base.uncheckElementPointedByCursor()
+
+ for (local i = GUI.Base.m_objects.len() - 1; i >= 0; --i)
+ {
+ local object = GUI.Base.m_objects[i]
+
+ if (!object.getVisible())
+ continue
+
+ if (object.m_isDisabled)
+ continue
+
+ if (object.m_visible && object.checkIsMouseAt())
+ {
+ if (object != elementPointedByCursor)
+ {
+ if (elementPointedByCursor)
+ GUI.Base.uncheckElementPointedByCursor()
+
+ elementPointedByCursor = object
+ callEvent("GUI.onMouseIn", object)
+ }
+ else
+ callEvent("GUI.onMouseMove", object, newCursorX, newCursorY, oldCursorX, oldCursorY)
+
+ break
+ }
+ else if (object == elementPointedByCursor)
+ GUI.Base.uncheckElementPointedByCursor()
+ }
+ }
+
+ static function onMouseClick(button)
+ {
+ if (elementPointedByCursor && !elementPointedByCursor.getVisible())
+ GUI.Base.uncheckElementPointedByCursor()
+
+ if (elementPointedByCursor)
+ {
+ if (elementPointedByCursor != focusedElement)
+ {
+ if (focusedElement)
+ focusedElement.loseFocus()
+
+ elementPointedByCursor.takeFocus()
+ }
+
+ elementPointedByCursor.m_lastButtonPressed = button
+ callEvent("GUI.onMouseDown", elementPointedByCursor, elementPointedByCursor.m_lastButtonPressed)
+ }
+ else if (focusedElement)
+ focusedElement.loseFocus()
+ }
+
+ static function onMouseRelease(button)
+ {
+ if (elementPointedByCursor)
+ {
+ callEvent("GUI.onMouseUp", elementPointedByCursor, elementPointedByCursor.m_lastButtonPressed)
+
+ if (elementPointedByCursor.m_lastButtonPressed == MOUSE_LMB)
+ callEvent("GUI.onClick", elementPointedByCursor)
+ }
+ }
+}
+
+addEventHandler("onRender", GUI.Base.onRender)
+addEventHandler("onMouseMove", GUI.Base.onMouseMove)
+addEventHandler("onMouseClick", GUI.Base.onMouseClick)
+addEventHandler("onMouseRelease", GUI.Base.onMouseRelease)
diff --git a/lib/gui-framework/abstract/margin.nut b/lib/gui-framework/abstract/margin.nut
new file mode 100644
index 0000000..d26de8c
--- /dev/null
+++ b/lib/gui-framework/abstract/margin.nut
@@ -0,0 +1,45 @@
+class GUI.Margin
+{
+#protected:
+ m_marginPx = null
+
+#public:
+ constructor()
+ {
+ m_marginPx =
+ {
+ top = 0,
+ right = 0
+ bottom = 0,
+ left = 0,
+ }
+ }
+
+ function getMarginPx()
+ {
+ return m_marginPx
+ }
+
+ function setMarginPx(top, right, bottom, left)
+ {
+ m_marginPx.top = top
+ m_marginPx.right = right
+ m_marginPx.bottom = bottom
+ m_marginPx.left = left
+ }
+
+ function getMargin()
+ {
+ return {
+ top = any(m_marginPx.top)
+ right = anx(m_marginPx.right)
+ bottom = any(m_marginPx.bottom)
+ left = anx(m_marginPx.left)
+ }
+ }
+
+ function setMargin(top, right, bottom, left)
+ {
+ setMarginPx(nay(top), nax(right), nay(bottom), nax(left))
+ }
+}
diff --git a/lib/gui-framework/abstract/offset.nut b/lib/gui-framework/abstract/offset.nut
new file mode 100644
index 0000000..6878650
--- /dev/null
+++ b/lib/gui-framework/abstract/offset.nut
@@ -0,0 +1,36 @@
+class GUI.Offset
+{
+#private:
+ m_offsetPx = null
+
+#public:
+ constructor()
+ {
+ m_offsetPx =
+ {
+ x = 0
+ y = 0
+ }
+ }
+
+ function getOffsetPx()
+ {
+ return m_offsetPx
+ }
+
+ function setOffsetPx(x, y)
+ {
+ m_offsetPx.x = x
+ m_offsetPx.y = y
+ }
+
+ function getOffset()
+ {
+ return {x = anx(m_offsetPx.x), y = any(m_offsetPx.y)}
+ }
+
+ function setOffset(x, y)
+ {
+ setOffsetPx(nax(x), nay(y))
+ }
+}
diff --git a/lib/gui-framework/abstract/orientation.nut b/lib/gui-framework/abstract/orientation.nut
new file mode 100644
index 0000000..9b339f1
--- /dev/null
+++ b/lib/gui-framework/abstract/orientation.nut
@@ -0,0 +1,16 @@
+class GUI.Orientation
+{
+#protected:
+ m_orientation = null
+
+#public:
+ function getOrientation()
+ {
+ return m_orientation
+ }
+
+ function setOrientation(orientation)
+ {
+ m_orientation = orientation
+ }
+}
diff --git a/lib/gui-framework/animation.nut b/lib/gui-framework/animation.nut
new file mode 100644
index 0000000..61080fc
--- /dev/null
+++ b/lib/gui-framework/animation.nut
@@ -0,0 +1,210 @@
+/*
+ Gui Framework
+ Author: Tommy and Patrix
+*/
+
+//animation type
+const EFFECT_ALPHA = 1;
+const EFFECT_SMOOTH_UP = 2;
+const EFFECT_SMOOTH_DOWN = 3;
+const EFFECT_SMOOTH_RIGHT = 4;
+const EFFECT_SMOOTH_LEFT = 5;
+
+const EFFECT_ALPHA_HIDE = 6;
+const EFFECT_SMOOTH_UP_HIDE = 7;
+const EFFECT_SMOOTH_DOWN_HIDE = 8;
+const EFFECT_SMOOTH_RIGHT_HIDE = 9;
+const EFFECT_SMOOTH_LEFT_HIDE = 10;
+
+//events
+addEvent("onAnimWindowEnd");
+
+class GUI.Animation
+{
+ static renderEventList = [];
+
+ constructor(_obj)
+ {
+ element = _obj;
+ time = 0.0;
+ type = null;
+ isActive = false;
+ deltaTime = 0;
+ miliSecond = 0;
+
+ renderEventList.append(this);
+ }
+
+ function change(_type, _time)
+ {
+ isActive = false;
+ time = _time.tofloat();
+ type = _type;
+ }
+
+ function play()
+ {
+ local pos = element.getPosition();
+ element.setPosition(pos.x, pos.y, false);
+
+ if(isActive)
+ isActive = false;
+
+ switch(type)
+ {
+ case EFFECT_ALPHA:
+ dimensions = {controlPoint = 0};
+ break;
+ case EFFECT_SMOOTH_UP:
+ dimensions = {
+ start = GuiVector2D(pos.x, 0 - element.getSize().height),
+ end = GuiVector2D(pos.x, pos.y),
+ controlPos = GuiVector2D(pos.x, 0 - element.getSize().height)
+ };
+ break;
+ case EFFECT_SMOOTH_DOWN:
+ dimensions = {
+ start = GuiVector2D(pos.x, getResolution().y + element.getSize().height),
+ end = GuiVector2D(pos.x, pos.y),
+ controlPos = GuiVector2D(pos.x, getResolution().y + element.getSize().height)
+ };
+ break;
+ case EFFECT_SMOOTH_LEFT:
+ dimensions = {
+ start = GuiVector2D(0 - element.getSize().width, pos.y),
+ end = GuiVector2D(pos.x, pos.y),
+ controlPos = GuiVector2D(0 - element.getSize().width, pos.y)
+ };
+ break;
+ case EFFECT_SMOOTH_RIGHT:
+ dimensions = {
+ start = GuiVector2D(getResolution().x + element.getSize().width, pos.y),
+ end = GuiVector2D(pos.x, pos.y),
+ controlPos = GuiVector2D(getResolution().x + element.getSize().width, pos.y)
+ };
+ break;
+ case EFFECT_ALPHA_HIDE:
+ dimensions = {controlPoint = 255};
+ break;
+ case EFFECT_SMOOTH_UP_HIDE:
+ dimensions = {
+ start = GuiVector2D(pos.x, pos.y),
+ end = GuiVector2D(pos.x, 0 - element.getSize().height),
+ controlPos = GuiVector2D(pos.x, pos.y)
+ };
+ break;
+ case EFFECT_SMOOTH_DOWN_HIDE:
+ dimensions = {
+ start = GuiVector2D(pos.x, pos.y),
+ end = GuiVector2D(pos.x, getResolution().y + element.getSize().height),
+ controlPos = GuiVector2D(pos.x, pos.y)
+ };
+ break;
+ case EFFECT_SMOOTH_RIGHT_HIDE:
+ dimensions = {
+ start = GuiVector2D(pos.x, pos.y),
+ end = GuiVector2D(getResolution().x + element.getSize().width, pos.y),
+ controlPos = GuiVector2D(pos.x, pos.y)
+ };
+ break;
+ case EFFECT_SMOOTH_LEFT_HIDE:
+ dimensions = {
+ start = GuiVector2D(pos.x, pos.y),
+ end = GuiVector2D(getResolution().x - element.getSize().width, pos.y),
+ controlPos = GuiVector2D(pos.x, pos.y)
+ };
+ break;
+ }
+
+ if(type != EFFECT_ALPHA && type != EFFECT_ALPHA_HIDE)
+ element.setPosition(dimensions.start.x, dimensions.start.y, false);
+
+ deltaTime = getTickCount();
+ miliSecond = 0;
+ isActive = true;
+ }
+
+ function getShow()//get type (hide/show)
+ {
+ if(type >= 1 && type <= 5)
+ return true;
+ else
+ return false;
+ }
+
+ static function calcSpeed(currPos, endPos)//temporary
+ {
+ return fabs(currPos - endPos) / time;
+ }
+
+ function follow()
+ {
+ ++miliSecond;
+
+ switch(type)
+ {
+ case EFFECT_ALPHA:
+ local speed = 255.0 / time
+ dimensions.controlPoint = dimensions.controlPoint + speed;
+ element.setAlpha(dimensions.controlPoint)
+ break;
+ case EFFECT_ALPHA_HIDE:
+ local speed = 255.0 / time
+ dimensions.controlPoint = dimensions.controlPoint - speed;
+ element.setAlpha(dimensions.controlPoint)
+ break;
+ case EFFECT_SMOOTH_UP:
+ case EFFECT_SMOOTH_DOWN_HIDE:
+ dimensions.controlPos.y = dimensions.controlPos.y + calcSpeed(element.parent.getPositionPx().y, dimensions.end.y) * miliSecond;
+ break;
+ case EFFECT_SMOOTH_DOWN:
+ case EFFECT_SMOOTH_UP_HIDE:
+ dimensions.controlPos.y = dimensions.controlPos.y - calcSpeed(element.parent.getPositionPx().y, dimensions.end.y) * miliSecond;
+ break;
+ case EFFECT_SMOOTH_LEFT:
+ case EFFECT_SMOOTH_RIGHT_HIDE:
+ dimensions.controlPos.x = dimensions.controlPos.x + calcSpeed(element.parent.getPositionPx().x, dimensions.end.x) * miliSecond;
+ break;
+ case EFFECT_SMOOTH_RIGHT:
+ case EFFECT_SMOOTH_LEFT_HIDE:
+ dimensions.controlPos.x = dimensions.controlPos.x - calcSpeed(element.parent.getPositionPx().x, dimensions.end.x) * miliSecond;
+ break;
+ }
+
+ if(type != EFFECT_ALPHA && type != EFFECT_ALPHA_HIDE)
+ element.setPosition(dimensions.controlPos.x, dimensions.controlPos.y, false);
+
+ if(miliSecond == time)
+ {
+ isActive = false;
+ callEvent("onAnimWindowEnd", element, type);
+ }
+ }
+
+ static function renderEvent()
+ {
+ foreach(object in GUI.Animation.renderEventList)
+ {
+ if(object.isActive)
+ {
+ if(object.deltaTime <= getTickCount())
+ {
+ object.deltaTime = getTickCount() - object.deltaTime + 1;
+ object.follow();
+ }
+ }
+ }
+ }
+
+ element = null;
+ time = null;
+ type = null;
+ dimensions = null;
+
+ isActive = false;
+
+ deltaTime = 0;
+ miliSecond = 0;
+}
+
+addEventHandler("onRender", GUI.Animation.renderEvent)
diff --git a/lib/gui-framework/elements/bar.nut b/lib/gui-framework/elements/bar.nut
new file mode 100644
index 0000000..debfd19
--- /dev/null
+++ b/lib/gui-framework/elements/bar.nut
@@ -0,0 +1,257 @@
+class GUI.Bar extends classes(GUI.Texture, GUI.Orientation, GUI.Alignment, GUI.Margin)
+{
+#proteced:
+ m_stretching = true
+
+ m_value = 0
+ m_minimum = 0
+ m_maximum = 100
+
+#public:
+ progress = null
+
+ constructor(x, y, width, height, marginX, marginY, background, progress, orientation = Orientation.Horizontal, alignment = Align.Left, window = null)
+ {
+ base.constructor(x, y, width, height, background, window)
+ setDisabled(true)
+
+ GUI.Orientation.setOrientation.call(this, orientation)
+ GUI.Alignment.setAlignment.call(this, alignment)
+ GUI.Margin.constructor.call(this)
+
+ this.progress = GUI.Texture(0, 0, 0, 0, progress)
+
+ setPosition(x, y)
+ setSize(width, height)
+
+ // tmp?
+ setMargin(marginY, marginX, marginY, marginX)
+ }
+
+ function getPercentage()
+ {
+ return fabs(m_value - m_minimum) / fabs(m_maximum - m_minimum)
+ }
+
+ function getValue()
+ {
+ return m_value
+ }
+
+ function setValue(value)
+ {
+ if (value > m_maximum)
+ value = m_maximum
+ else if (value < m_minimum)
+ value = m_minimum
+
+ m_value = value
+
+ local maxSize = getSizePx()
+ setSizePx(maxSize.width, maxSize.height)
+ }
+
+ function getMinimum()
+ {
+ return m_minimum
+ }
+
+ function setMinimum(minimum)
+ {
+ m_minimum = minimum
+ setValue(m_minimum)
+ }
+
+ function getMaximum()
+ {
+ return m_maximum
+ }
+
+ function setMaximum(maximum)
+ {
+ m_maximum = maximum
+ setValue(m_minimum)
+ }
+
+ function top()
+ {
+ base.top()
+ progress.top()
+ }
+
+ function destroy()
+ {
+ base.destroy()
+ progress.destroy()
+ }
+
+ function getStreching()
+ {
+ return m_stretching
+ }
+
+ function setStretching(stretching)
+ {
+ m_stretching = stretching
+ }
+
+ function setAlignment(alignment)
+ {
+ GUI.Alignment.setAlignment.call(this, alignment)
+
+ local position = getPositionPx()
+ setPositionPx(position.x, position.y)
+
+ setValue(getValue())
+ }
+
+ function setVisible(visible)
+ {
+ base.setVisible(visible)
+ progress.setVisible(visible)
+ }
+
+ function setAlpha(alpha)
+ {
+ base.setAlpha(alpha)
+ progress.setAlpha(alpha)
+ }
+
+ function setPositionPx(x, y)
+ {
+ base.setPositionPx(x, y)
+
+ local size = getSizePx()
+
+ if (m_orientation == Orientation.Horizontal)
+ {
+ local progressWidth = ((size.width - m_marginPx.left - m_marginPx.right) * getPercentage()).tointeger()
+
+ switch (m_alignment)
+ {
+ case Align.Left:
+ progress.setPositionPx(x + m_marginPx.left, y + m_marginPx.top)
+ break
+
+ case Align.Right:
+ progress.setPositionPx(x + (size.width - progressWidth) - m_marginPx.right, y + m_marginPx.top)
+ break
+
+ case Align.Center:
+ progress.setPositionPx(x + (size.width - progressWidth) / 2, y + m_marginPx.top)
+ break
+ }
+ }
+ else if (m_orientation == Orientation.Vertical)
+ {
+ local progressHeight = ((size.height - m_marginPx.top - m_marginPx.bottom) * getPercentage()).tointeger()
+
+ switch (m_alignment)
+ {
+ case Align.Left:
+ progress.setPositionPx(x + m_marginPx.left, y + m_marginPx.top)
+ break
+
+ case Align.Right:
+ progress.setPositionPx(x + m_marginPx.left, y + size.height - progressHeight - m_marginPx.bottom)
+ break
+
+ case Align.Center:
+ progress.setPositionPx(x + m_marginPx.right, y + (size.height - progressHeight) / 2)
+ break
+ }
+ }
+ }
+
+ function setPosition(x, y)
+ {
+ setPositionPx(nax(x), nay(y))
+ }
+
+ function changeProgress(rectX, rectY, rectWidth, rectHeight)
+ {
+ if (!m_stretching)
+ {
+ local size = getSizePx()
+
+ progress.setSizePx((size.width - m_marginPx.left - m_marginPx.right), size.height - m_marginPx.top - m_marginPx.bottom)
+ progress.setRectPx(rectX, rectY, rectWidth, rectHeight)
+ }
+
+ progress.setSizePx(rectWidth, rectHeight)
+ }
+
+ function setSizePx(width, height)
+ {
+ base.setSizePx(width, height)
+
+ local position = getPositionPx()
+
+ local progressWidth = width - m_marginPx.left - m_marginPx.right
+ local progressHeight = height - m_marginPx.top - m_marginPx.bottom
+
+ if (m_orientation == Orientation.Horizontal)
+ {
+ progressWidth = (progressWidth * getPercentage()).tointeger()
+
+ switch (m_alignment)
+ {
+ case Align.Left:
+ changeProgress(0, 0, progressWidth, progressHeight)
+ break
+
+ case Align.Right:
+ changeProgress(width - progressWidth - m_marginPx.left - m_marginPx.right, 0, progressWidth, progressHeight)
+ setPositionPx(position.x, position.y)
+ break
+
+ case Align.Center:
+ changeProgress((width - progressWidth - m_marginPx.left - m_marginPx.right) / 2, 0, progressWidth, progressHeight)
+ setPositionPx(position.x, position.y)
+ break
+ }
+ }
+ else if (m_orientation == Orientation.Vertical)
+ {
+ progressHeight = (progressHeight * getPercentage()).tointeger()
+
+ switch (m_alignment)
+ {
+ case Align.Left:
+ changeProgress(0, 0, progressWidth, progressHeight)
+ break
+
+ case Align.Right:
+ changeProgress(0, height - progressHeight - m_marginPx.top - m_marginPx.bottom, progressWidth, progressHeight)
+ setPositionPx(position.x, position.y)
+ break
+
+ case Align.Center:
+ changeProgress(0, (height - progressHeight - m_marginPx.top - m_marginPx.bottom) / 2, progressWidth, progressHeight)
+ setPositionPx(position.x, position.y)
+ break
+ }
+ }
+ }
+
+ function setSize(width, height)
+ {
+ setSizePx(nax(width), nay(height))
+ }
+
+ function setMarginPx(top, right, bottom, left)
+ {
+ GUI.Margin.setMarginPx.call(this, top, right, bottom, left)
+
+ local position = getPositionPx()
+ local size = getSizePx()
+
+ setPositionPx(position.x, position.y)
+ setSizePx(size.width, size.height)
+ }
+
+ function setMargin(top, right, bottom, left)
+ {
+ setMarginPx(nay(top), nax(right), nay(bottom), nax(left))
+ }
+}
diff --git a/lib/gui-framework/elements/button.nut b/lib/gui-framework/elements/button.nut
new file mode 100644
index 0000000..2cdd514
--- /dev/null
+++ b/lib/gui-framework/elements/button.nut
@@ -0,0 +1,122 @@
+class GUI.Button extends classes(GUI.Texture, GUI.Alignment, GUI.Offset)
+{
+#public:
+ draw = null
+
+ constructor(x, y, width, height, file, text = null, window = null)
+ {
+ base.constructor(x, y, width, height, file, window)
+
+ if (text != null)
+ {
+ draw = GUI.Draw(0, 0, text)
+ draw.setDisabled(true)
+
+ GUI.Offset.constructor.call(this)
+ setAlignment(Align.Center)
+ }
+ }
+
+ function destroy()
+ {
+ if (draw)
+ draw = draw.destroy()
+
+ base.destroy()
+ }
+
+ function setOffsetPx(x, y)
+ {
+ GUI.Offset.setOffsetPx.call(this, x, y)
+ setAlignment(getAlignment())
+ }
+
+ function setOffset(x, y)
+ {
+ setOffsetPx(nax(x), nay(y))
+ }
+
+ function setAlignment(alignment)
+ {
+ GUI.Alignment.setAlignment.call(this, alignment)
+
+ local position = getPositionPx()
+ local size = getSizePx()
+
+ switch (alignment)
+ {
+ case Align.Left:
+ draw.leftPx(position.x + m_offsetPx.x, position.y + m_offsetPx.y, size.width, size.height)
+ break
+
+ case Align.Center:
+ draw.centerPx(position.x + m_offsetPx.x, position.y + m_offsetPx.y, size.width, size.height)
+ break
+
+ case Align.Right:
+ draw.rightPx(position.x + m_offsetPx.x, position.y + m_offsetPx.y, size.width, size.height)
+ break
+ }
+ }
+
+ function setVisible(visible)
+ {
+ base.setVisible(visible)
+
+ if (draw)
+ draw.setVisible(visible)
+ }
+
+ function setAlpha(alpha)
+ {
+ base.setAlpha(alpha)
+
+ if (draw)
+ draw.setAlpha(alpha)
+ }
+
+ function top()
+ {
+ base.top()
+
+ if (draw)
+ draw.top()
+ }
+
+ function setPositionPx(x, y)
+ {
+ base.setPositionPx(x, y)
+
+ if (draw)
+ setAlignment(getAlignment())
+ }
+
+ function setPosition(x, y)
+ {
+ setPositionPx(nax(x), nay(y))
+ }
+
+ function setSizePx(width, height)
+ {
+ base.setSizePx(width, height)
+
+ if (draw)
+ setAlignment(getAlignment())
+ }
+
+ function setSize(x, y)
+ {
+ setSizePx(nax(x), nay(y))
+ }
+
+ function getText()
+ {
+ return draw.getText()
+ }
+
+ function setText(text)
+ {
+ draw.setText(text)
+ setAlignment(getAlignment())
+ }
+}
diff --git a/lib/gui-framework/elements/checkbox.nut b/lib/gui-framework/elements/checkbox.nut
new file mode 100644
index 0000000..953be53
--- /dev/null
+++ b/lib/gui-framework/elements/checkbox.nut
@@ -0,0 +1,104 @@
+class GUI.CheckBox extends GUI.Button
+{
+#protected:
+ m_originalTexture = null
+ m_selector = null
+
+ m_checked = false
+ m_enableDeselection = true
+
+#public:
+ constructor(x, y, width, height, file, selector, window = null)
+ {
+ if (selector.len() >= 4 && selector.slice(selector.len() - 4).toupper() == ".TGA")
+ {
+ base.constructor(x, y, width, height, file, null, window)
+ m_originalTexture = file
+ }
+ else
+ {
+ base.constructor(x, y, width, height, file, selector, window)
+ }
+
+ m_selector = selector
+ }
+
+ function setText(text)
+ {
+ base.setText(text)
+
+ if (draw)
+ m_selector = text
+ }
+
+ function setVisible(visible)
+ {
+ GUI.Texture.setVisible.call(this, visible)
+
+ if (draw && m_checked)
+ draw.setVisible(visible)
+ }
+
+ function setFile(file)
+ {
+ if (draw)
+ base.setFile(file)
+ else
+ {
+ if (!m_checked)
+ base.setFile(file)
+ else
+ m_originalTexture = file
+ }
+ }
+
+ function getChecked()
+ {
+ return m_checked
+ }
+
+ function setChecked(checked)
+ {
+ m_checked = checked
+
+ if (draw)
+ {
+ if (m_visible)
+ draw.setVisible(checked)
+ }
+ else
+ file = (checked) ? m_selector : m_originalTexture
+ }
+
+ function getSelector()
+ {
+ return m_selector
+ }
+
+ function setSelector(text)
+ {
+ if (draw)
+ draw.setText(text)
+ else
+ m_selector = text
+ }
+
+ function enableDeselection(deselection)
+ {
+ m_enableDeselection = deselection
+ }
+
+ static function onClick(self)
+ {
+ if (!(self instanceof GUI.CheckBox))
+ return
+
+ if (self.m_checked && !self.m_enableDeselection)
+ return
+
+ self.m_checked = !self.m_checked
+ self.setChecked(self.m_checked)
+ }
+}
+
+addEventHandler("GUI.onClick", GUI.CheckBox.onClick)
diff --git a/lib/gui-framework/elements/collection.nut b/lib/gui-framework/elements/collection.nut
new file mode 100644
index 0000000..2fa9c14
--- /dev/null
+++ b/lib/gui-framework/elements/collection.nut
@@ -0,0 +1,99 @@
+class GUI.Collection
+{
+#private:
+ m_positionPx = null
+
+#public:
+ childs = null
+
+ constructor(x, y)
+ {
+ m_positionPx = { x = nax(x), y = nay(y) }
+ childs = {}
+ }
+
+ function insert(pointer)
+ {
+ if (pointer in childs)
+ return
+
+ local bodyPos = getPositionPx()
+ local childPos = pointer.getPositionPx()
+
+ childs[pointer] <- GUI.Vector2D(childPos.x, childPos.y)
+ pointer.setPositionPx(bodyPos.x + childPos.x, bodyPos.y + childPos.y)
+ }
+
+ function remove(pointer)
+ {
+ delete childs[pointer]
+ }
+
+ function getPositionPx()
+ {
+ return m_positionPx
+ }
+
+ function getPosition()
+ {
+ return { x = nax(m_positionPx.x), y = nay(m_positionPx.y) }
+ }
+
+ function setPosition(x, y)
+ {
+ setPositionPx(nax(x), nay(y))
+ }
+
+ function setPositionPx(x, y)
+ {
+ m_positionPx.x = x
+ m_positionPx.y = y
+
+ foreach(item, offset in childs)
+ item.setPositionPx(offset.x + x, offset.y + y)
+ }
+
+ function getChildPositionPx(pointer)
+ {
+ return childs[pointer]
+ }
+
+ function setChildPositionPx(pointer, x, y)
+ {
+ local bodyPos = getPositionPx()
+
+ childs[pointer].x = x
+ childs[pointer].y = y
+
+ pointer.setPositionPx(bodyPos.x + x, bodyPos.y + y)
+ }
+
+ function getChildPosition(pointer)
+ {
+ local position = getChildPositionPx(pointer)
+ return {x = anx(position.x), y = anx(position.y)}
+ }
+
+ function setChildPosition(pointer, x, y)
+ {
+ setChildPositionPx(pointer, nax(x), nay(y))
+ }
+
+ function setVisible(visible)
+ {
+ foreach (item, offset in childs)
+ item.setVisible(visible)
+ }
+
+ function top()
+ {
+ foreach (item, offset in childs)
+ item.top()
+ }
+
+ function destroy()
+ {
+ foreach (item, offset in childs)
+ item.destroy()
+ }
+}
diff --git a/lib/gui-framework/elements/draw.nut b/lib/gui-framework/elements/draw.nut
new file mode 100644
index 0000000..00727a7
--- /dev/null
+++ b/lib/gui-framework/elements/draw.nut
@@ -0,0 +1,391 @@
+class GUI.Draw extends GUI.Base
+{
+#private:
+ m_positionPx = null
+ m_sizePx = null
+ m_letterSpacingPx = 0
+ m_lineSizePx = null
+
+ m_text = ""
+ m_font = "FONT_OLD_10_WHITE_HI.TGA"
+
+ m_color = null
+ m_alpha = 255
+
+#public:
+ letters = null
+
+ constructor(x, y, text, window = null)
+ {
+ base.constructor()
+
+ letters = []
+ m_color = {r = 255, g = 255, b = 255}
+
+ m_positionPx = {x = nax(x), y = nay(y)}
+ m_sizePx = {width = 0, height = 0}
+
+ setText(text)
+
+ if (window)
+ window.insert(this)
+ }
+
+ function leftPx(x, y, width, height)
+ {
+ local size = getSizePx()
+
+ if (!size.width && !size.height)
+ return
+
+ centerPx(x, y, width, height)
+
+ local position = getPositionPx()
+ setPositionPx(x, position.y)
+ }
+
+ function left(x, y)
+ {
+ leftPx(nax(x), nay(y))
+ }
+
+ function centerPx(x, y, width, height)
+ {
+ local size = getSizePx()
+
+ if (!size.width && !size.height)
+ return
+
+ local centerX = x + (width - size.width) / 2
+ local centerY = y + (height - size.height) / 2
+
+ if (centerX > 0)
+ m_positionPx.x = centerX
+
+ if (centerY > 0)
+ m_positionPx.y = centerY
+
+ setPositionPx(centerX, centerY)
+ }
+
+ function center(x, y, width, height)
+ {
+ centerPx(nax(x), nay(y), nax(width), nay(height))
+ }
+
+ function rightPx(x, y, width, height)
+ {
+ local size = getSizePx()
+
+ if (!size.width && !size.height)
+ return
+
+ centerPx(x, y, width, height)
+ local position = getPositionPx()
+
+ local rightX = x + (width - size.width)
+ setPositionPx(rightX, position.y)
+ }
+
+ function right(x, y, width, height)
+ {
+ rightPx(nax(x), nay(y), nax(width), nay(height))
+ }
+
+ function setVisible(visible)
+ {
+ base.setVisible(visible)
+
+ foreach (letter in letters)
+ letter.visible = visible
+ }
+
+ function getPositionPx()
+ {
+ return m_positionPx
+ }
+
+ function setPositionPx(x, y, beginLetter = 0, endLetter = -1)
+ {
+ if (endLetter == -1)
+ {
+ m_positionPx.x = x
+ m_positionPx.y = y
+
+ endLetter = letters.len() - 1
+ }
+
+ m_sizePx.width = 0
+ local width = 0, height = 0
+
+ for (local i = beginLetter; i <= endLetter; ++i)
+ {
+ letters[i].setPositionPx(x + width, y + height)
+ width += letters[i].widthPx + m_letterSpacingPx
+
+ if (letters[i].text == "\n")
+ {
+ if (width > m_sizePx.width)
+ m_sizePx.width = width
+
+ width = 0
+ height += getLineSizePx()
+ }
+ }
+
+ if (width > m_sizePx.width)
+ m_sizePx.width = width
+
+ m_sizePx.height = height + getLineSizePx()
+ }
+
+ function getPosition()
+ {
+ return {x = anx(m_positionPx.x), y = any(m_positionPx.y)}
+ }
+
+ function setPosition(x, y, beginLetter = 0, endLetter = -1)
+ {
+ setPositionPx(nax(x), nay(y), beginLetter, endLetter)
+ }
+
+ function getSizePx()
+ {
+ return m_sizePx
+ }
+
+ function getSize()
+ {
+ return {width = anx(m_sizePx.width), height = any(m_sizePx.height)}
+ }
+
+ function getLineSizePx()
+ {
+ if (m_lineSizePx)
+ return m_lineSizePx
+
+ textSetFont(m_font)
+ return textHeightPx("")
+ }
+
+ function setLineSizePx(lineSize)
+ {
+ m_lineSizePx = lineSize
+ setPositionPx(m_positionPx.x, m_positionPx.y)
+ }
+
+ function getLineSize()
+ {
+ return any(getLineSizePx())
+ }
+
+ function setLineSize(lineSize)
+ {
+ setLineSizePx(any(lineSize))
+ }
+
+ function getLinesCount()
+ {
+ return getSizePx().height / getLineSizePx()
+ }
+
+ function getLetterSpacingPx()
+ {
+ return m_letterSpacingPx
+ }
+
+ function setLetterSpacingPx(spacing)
+ {
+ m_letterSpacingPx = spacing
+ setPositionPx(m_positionPx.x, m_positionPx.y)
+ }
+
+ function getLetterSpacing()
+ {
+ return nax(m_letterSpacingPx)
+ }
+
+ function setLetterSpacing(spacing)
+ {
+ setLetterSpacingPx(nax(spacing))
+ }
+
+ function resize(size)
+ {
+ if (DRAW_SHRINK_TO_FIT)
+ return
+
+ local lettersLen = letters.len()
+
+ for (local i = lettersLen; i < size; ++i)
+ {
+ letters.push( Draw(anx(0), any(0), "") )
+
+ letters[i].setColor(m_color.r, m_color.g, m_color.b)
+ letters[i].setAlpha(m_alpha)
+ }
+
+ if (lettersLen > size)
+ {
+ for (local i = lettersLen; i >= size; --i)
+ letters.pop()
+
+ setText(m_text.slice(0, size))
+ }
+ }
+
+ function top()
+ {
+ base.top()
+
+ foreach (letter in letters)
+ letter.top()
+ }
+
+ function parseColor(text)
+ {
+ local regex = regexp(@"\[#[0-9_a-f_A-F]{6,}]")
+
+ local currentPosition = 0
+
+ local outputString = ""
+ local colorInfo = []
+
+ local result
+
+ while (result = regex.search(text, currentPosition))
+ {
+ local substring = text.slice(currentPosition, result.begin)
+ local color = text.slice(result.begin + 2, result.end - 1)
+
+ colorInfo.push({begin = result.begin - colorInfo.len() * 9, color = hexToRgb(color)})
+
+ outputString += substring
+ currentPosition = result.end
+ }
+
+ outputString += text.slice(currentPosition, text.len())
+ m_text = outputString
+
+ if (colorInfo.len() && colorInfo[0].begin > 0)
+ colorInfo.insert(0, {begin = 0, color = m_color})
+
+ return {colorInfo = colorInfo, outputString = outputString}
+ }
+
+ function getText()
+ {
+ return m_text
+ }
+
+ function setText(text, colorParserEnabled = true)
+ {
+ if (typeof text != "string")
+ text = text.tostring()
+
+ local currentColorIndex = null
+ local colorInfo
+
+ if (colorParserEnabled)
+ {
+ local result = parseColor(text)
+
+ colorInfo = result.colorInfo
+ text = result.outputString
+
+ currentColorIndex = 0
+ }
+
+ m_text = text
+
+ local textLen = text.len()
+
+ for (local i = 0; i < textLen; ++i)
+ {
+ local letter = text.slice(i, i + 1)
+
+ if (!(i in letters))
+ {
+ letters.push( Draw(anx(0), any(0), "") )
+
+ letters[i].setColor(m_color.r, m_color.g, m_color.b)
+ letters[i].setAlpha(m_alpha)
+ }
+
+ if (colorParserEnabled && colorInfo.len())
+ {
+ if (currentColorIndex + 1 in colorInfo && i == colorInfo[currentColorIndex + 1].begin)
+ currentColorIndex += 1
+
+ letters[i].setColor(colorInfo[currentColorIndex].color.r, colorInfo[currentColorIndex].color.g, colorInfo[currentColorIndex].color.b)
+ }
+
+ letters[i].font = m_font
+ letters[i].text = letter
+ letters[i].visible = m_visible
+ }
+
+ for (local j = letters.len() - 1; j >= textLen; --j)
+ {
+ if (DRAW_SHRINK_TO_FIT)
+ letters.pop()
+ else
+ letters[j].text = ""
+ }
+
+ setPositionPx(m_positionPx.x, m_positionPx.y)
+ }
+
+ function getFont()
+ {
+ return m_font
+ }
+
+ function setFont(font)
+ {
+ if (font == m_font)
+ return
+
+ m_font = font
+
+ setText(getText())
+ }
+
+ function getColor()
+ {
+ return m_color
+ }
+
+ function setColor(r, g, b, beginLetter = 0, endLetter = -1)
+ {
+ if (endLetter == -1)
+ {
+ m_color.r = r
+ m_color.g = g
+ m_color.b = b
+
+ endLetter = letters.len() - 1
+ }
+
+ for (local i = beginLetter; i <= endLetter; ++i)
+ letters[i].setColor(r, g, b)
+ }
+
+ function getAlpha()
+ {
+ return m_alpha
+ }
+
+ function setAlpha(alpha, beginLetter = 0, endLetter = -1)
+ {
+ if (endLetter == -1)
+ {
+ m_alpha = alpha
+
+ endLetter = letters.len() -1
+ }
+
+ for (local i = beginLetter; i <= endLetter; ++i)
+ letters[i].setAlpha(alpha)
+ }
+}
diff --git a/lib/gui-framework/elements/gridlist.nut b/lib/gui-framework/elements/gridlist.nut
new file mode 100644
index 0000000..811d464
--- /dev/null
+++ b/lib/gui-framework/elements/gridlist.nut
@@ -0,0 +1,495 @@
+class GUI.GridListCell extends GUI.Button
+{
+ m_value = null
+
+ constructor(x, y, width, height, file, value)
+ {
+ base.constructor(x, y, width, height, file, value)
+ setValue(value)
+ }
+
+ function getValue()
+ {
+ return (m_value != null) ? m_value : getText()
+ }
+
+ function setValue(value)
+ {
+ m_value = value
+ setText(value)
+ }
+}
+
+class GUI.GridListRow
+{
+#private:
+ m_visible = false
+
+#public:
+ id = -1
+
+ parent = null
+ cells = null
+
+ function destroy()
+ {
+ foreach (index, _ in cells)
+ {
+ if (cells[index])
+ cells[index] = cells[index].destroy()
+ }
+ }
+
+ function insertCell(cellId, text)
+ {
+ if (cells[cellId])
+ return
+
+ local cell = GUI.GridListCell(0, 0, parent.columns[cellId].width, any(parent.m_rowSizePx), "", text)
+ cell.parent = this
+
+ cell.setAlignment(parent.columns[cellId].getAlignment())
+
+ local offset = parent.columns[cellId].getOffsetPx()
+ cell.setOffsetPx(offset.x, offset.y)
+
+ cells[cellId] = cell
+
+ if (m_visible)
+ {
+ cell.setVisible(true)
+
+ if (cellId >= parent.m_currentPosition && cellId < parent.m_currentPosition + parent.getMaximumVisibleRows())
+ parent.refreshList()
+ }
+
+ return cell
+ }
+
+ function removeCell(cellId)
+ {
+ if (!cells[cellId])
+ return
+
+ cells[cellId] = cells[cellId].destroy()
+ }
+
+ function setPositionPx(x, y)
+ {
+ local width = 0
+
+ for (local i = 0; i < parent.columns.len(); ++i)
+ {
+ if (cells[i])
+ cells[i].setPositionPx(x + nax(width), y)
+
+ width += parent.columns[i].width
+ }
+ }
+
+ function setPosition(x, y)
+ {
+ setPositionPx(nax(x), nay(y))
+ }
+
+ function getVisible()
+ {
+ return m_visible
+ }
+
+ function setVisible(visible)
+ {
+ m_visible = visible
+
+ foreach (cell in cells)
+ {
+ if (cell)
+ cell.setVisible(visible)
+ }
+ }
+}
+
+class GUI.GridListColumn extends GUI.Button
+{
+#public:
+ id = -1
+ width = 0
+
+ constructor (x, y, width, height, text = null)
+ {
+ base.constructor(x, y, 0, 0, "", text)
+
+ local drawSize = draw.getSize()
+
+ if (!width)
+ width = drawSize.width
+
+ if (!height)
+ height = drawSize.height
+
+ this.width = width
+
+ setSize(width, height)
+ }
+
+ function destroy()
+ {
+ base.destroy()
+
+ foreach (index, _ in parent.rows)
+ {
+ parent.rows[index].removeCell(id)
+ parent.rows[index].cells.remove(id)
+ }
+ }
+
+ function setAlignment(alignment)
+ {
+ local oldAlignment = getAlignment()
+
+ base.setAlignment(alignment)
+
+ if (!parent)
+ return
+
+ if (oldAlignment == alignment)
+ return
+
+ foreach (row in parent.rows)
+ {
+ if (row.cells[id])
+ row.cells[id].setAlignment(alignment)
+ }
+ }
+
+ function setOffsetPx(x, y)
+ {
+ base.setOffsetPx(x, y)
+
+ if (!parent)
+ return
+
+ foreach (row in parent.rows)
+ {
+ if (row.cells[id])
+ row.cells[id].setOffsetPx(x, y)
+ }
+ }
+
+ function setOffset(x, y)
+ {
+ setOffsetPx(nax(x), nay(y))
+ }
+}
+
+class GUI.GridList extends classes(GUI.Texture, GUI.Margin)
+{
+#private:
+ m_currentPosition = 0
+
+ m_rowSizePx = 0
+ m_spacingPx = 0
+
+#public:
+ columns = null
+ rows = null
+
+ scrollbar = null
+
+ constructor(x, y, w, h, bodyBg, scrollBg, scrollIndicator, scrollIncreaseBtn, scrollDecreaseBtn, window = null)
+ {
+ columns = []
+ rows = []
+
+ GUI.Margin.constructor.call(this)
+
+ scrollbar = GUI.ScrollBar(x + w - anx(GRIDLIST_SCROLLBAR_SIZE), y, anx(GRIDLIST_SCROLLBAR_SIZE), h, scrollBg, scrollIndicator, scrollIncreaseBtn, scrollDecreaseBtn, Orientation.Vertical)
+ base.constructor(x, y, w, h, bodyBg, window)
+
+ scrollbar.parent = this
+ scrollbar.setMinimum(0)
+ scrollbar.setMaximum(0)
+ scrollbar.top()
+
+ textSetFont("FONT_OLD_10_WHITE_HI.TGA")
+ m_rowSizePx = textHeightPx("x")
+ }
+
+ function destroy()
+ {
+ foreach(index, _ in columns)
+ columns[index] = columns[index].destroy()
+
+ foreach (index, _ in rows)
+ rows[index] = rows[index].destroy()
+
+ scrollbar = scrollbar.destroy()
+ base.destroy()
+ }
+
+ function setPositionPx(x, y)
+ {
+ base.setPositionPx(x, y)
+ scrollbar.setPositionPx(x + getSizePx().width - GRIDLIST_SCROLLBAR_SIZE, y)
+
+ refreshColumns()
+ refreshList()
+ }
+
+ function setPosition(x, y)
+ {
+ setPositionPx(nax(x), nay(y))
+ }
+
+ function insertColumn(index, text, width = null, align = Align.Center)
+ {
+ local position = getPosition()
+ local margin = getMargin()
+
+ for (local i = 0; i < index; ++i)
+ margin.left += columns[i].getSize().width
+
+ local column = GUI.GridListColumn(position.x + margin.left, position.y + margin.top, width, null, text)
+
+ column.setAlignment(align)
+ column.setVisible(visible)
+
+ column.id = index
+ column.parent = this
+
+ columns.insert(index, column)
+
+ foreach (row in rows)
+ {
+ if (!(index in row))
+ row.cells.insert(index, null)
+ }
+
+ return column
+ }
+
+ function addColumn(text, width = null, align = Align.Center)
+ {
+ return insertColumn(columns.len(), text, width, align)
+ }
+
+ function removeColumn(columnId)
+ {
+ for (local i = columns.len() - 1; i > columnId; --i)
+ --columns[i].id
+
+ columns[columnId].destroy()
+ columns.remove(columnId)
+
+ if (!columns.len())
+ scrollbar.setMaximum(0)
+ else
+ {
+ refreshColumns()
+ refreshList()
+ }
+ }
+
+ function insertRow(rowId, ...)
+ {
+ local row = GUI.GridListRow()
+
+ row.id = rowId
+ row.parent = this
+
+ row.cells = array(columns.len(), null)
+
+ rows.insert(rowId, row)
+
+ for (local i = columns.len() - 1; i >= 0; --i)
+ rows[rowId].insertCell(i, vargv[i])
+
+ local maximumVisibleRows = getMaximumVisibleRows()
+
+ if (rows.len() > maximumVisibleRows)
+ scrollbar.setMaximum(scrollbar.getMaximum() + 1)
+
+ if (rowId < m_currentPosition + maximumVisibleRows)
+ refreshList()
+
+ return row
+ }
+
+ function addRow(...)
+ {
+ vargv.insert(0, this)
+ vargv.insert(1, rows.len())
+
+ return insertRow.acall(vargv)
+ }
+
+ function removeRow(rowId)
+ {
+ for (local i = rows.len() - 1; i > rowId; --i)
+ --rows[i].id
+
+ rows[rowId].destroy()
+ rows.remove(rowId)
+
+ local maximumVisibleRows = getMaximumVisibleRows()
+
+ if (rows.len() >= maximumVisibleRows)
+ scrollbar.setMaximum(scrollbar.getMaximum() - 1)
+
+ if (rowId >= m_currentPosition && rowId < m_currentPosition + maximumVisibleRows)
+ refreshList()
+ }
+
+ function setVisible(visible)
+ {
+ base.setVisible(visible)
+ scrollbar.setVisible(visible)
+
+ foreach (column in columns)
+ column.setVisible(visible)
+
+ refreshList()
+ }
+
+ function setMarginPx(top, right, bottom, left)
+ {
+ hideOldRows()
+ GUI.Margin.setMarginPx.call(this, top, right, bottom, left)
+ showNewRows()
+ }
+
+ function setMargin(top, right, bottom, left)
+ {
+ setMarginPx(nay(top), nax(right), nay(bottom), nax(left))
+ }
+
+ function getRowSizePx()
+ {
+ return m_rowSizePx
+ }
+
+ function setRowSizePx(rowSize)
+ {
+ m_rowSizePx = rowSize
+
+ foreach (row in rows)
+ {
+ foreach (id, cell in row.cells)
+ cell.setSizePx(columns[id].getSizePx().width, rowSize)
+ }
+ }
+
+ function getRowSize()
+ {
+ return nay(m_rowSizePx)
+ }
+
+ function setRowSize(rowSize)
+ {
+ setRowSizePx(nay(rowSize))
+ }
+
+ function getSpacingPx()
+ {
+ return m_spacingPx
+ }
+
+ function setSpacingPx(spacing)
+ {
+ m_spacingPx = spacing
+ refreshList()
+ }
+
+ function getSpacing()
+ {
+ return nay(m_spacingPx)
+ }
+
+ function setSpacing(spacing)
+ {
+ setSpacingPx(nay(spacing))
+ }
+
+ function sort(func)
+ {
+ hideOldRows()
+ rows.sort(func)
+ showNewRows()
+ }
+
+ function getMaximumVisibleRows()
+ {
+ local rowSize = m_rowSizePx + m_spacingPx
+ return (getSizePx().height - rowSize - m_marginPx.top - m_marginPx.bottom) / rowSize
+ }
+
+ function hideOldRows()
+ {
+ if (!columns.len())
+ return
+
+ for (local i = m_currentPosition, end = m_currentPosition + getMaximumVisibleRows(); i < end && (i in rows); ++i)
+ rows[i].setVisible(false)
+ }
+
+ function showNewRows()
+ {
+ if (!visible)
+ return
+
+ if (!columns.len())
+ return
+
+ local rowSize = m_rowSizePx + m_spacingPx
+ local position = getPositionPx()
+
+ position.x += m_marginPx.left
+ position.y += m_marginPx.top
+
+ m_currentPosition = scrollbar.getValue()
+
+ for (local i = m_currentPosition, end = m_currentPosition + getMaximumVisibleRows(); i < end && (i in rows); ++i)
+ {
+ position.y += rowSize
+
+ rows[i].setPositionPx(position.x, position.y)
+ rows[i].setVisible(true)
+ }
+ }
+
+ function refreshList()
+ {
+ if (!columns.len())
+ return
+
+ hideOldRows()
+ showNewRows()
+ }
+
+ function refreshColumns()
+ {
+ local position = getPositionPx()
+
+ position.x += m_marginPx.left
+ position.y += m_marginPx.top
+
+ foreach (column in columns)
+ {
+ column.setPositionPx(position.x, position.y)
+ position.x += nax(column.width)
+ }
+ }
+
+ static function onChange(self)
+ {
+ if (!(self instanceof GUI.ScrollBar))
+ return
+
+ if (!(self.parent instanceof GUI.GridList))
+ return
+
+ self.parent.refreshList()
+ }
+}
+
+addEventHandler("GUI.onChange", GUI.GridList.onChange)
diff --git a/lib/gui-framework/elements/input.nut b/lib/gui-framework/elements/input.nut
new file mode 100644
index 0000000..5bc15d9
--- /dev/null
+++ b/lib/gui-framework/elements/input.nut
@@ -0,0 +1,263 @@
+enum Input
+{
+ Text,
+ Password,
+ Numbers
+}
+
+addEvent("GUI.onInputInsertLetter")
+addEvent("GUI.onInputRemoveLetter")
+addEvent("GUI.onInputActive")
+addEvent("GUI.onInputDeactive")
+
+class GUI.Input extends GUI.Texture
+{
+ static InputsList = []
+
+#private:
+ m_distance = null
+ m_type = null
+ m_align = null
+ m_placeholder = ""
+ m_margin = 2
+ m_text = ""
+ m_active = false
+#public:
+ draw = null
+ distance = null
+ selector = "|"
+ maxLetters = 1000
+
+ constructor(x, y, w, h, file, font, type, align = Align.Left, placeholder = "", margin = 2, window = null)
+ {
+ draw = GUI.Draw(x, y, placeholder)
+ draw.setFont(font)
+
+ m_placeholder = placeholder
+ m_align = align
+ m_type = type
+ m_margin = margin
+ m_text = ""
+ m_active = false
+
+ base.constructor(x, y, w, h, file, window)
+ draw.top()
+
+ alignText()
+ InputsList.append(this)
+ }
+
+ function alignText()
+ {
+ local pos = base.getPositionPx()
+ local size = base.getSizePx()
+ local sizeDraw = draw.getSizePx()
+ switch(m_align)
+ {
+ case Align.Left:
+ draw.setPositionPx(pos.x + m_margin, pos.y + size.height/2 - sizeDraw.height/2)
+ break
+ case Align.Center:
+ draw.setPositionPx(pos.x + size.width/2 - sizeDraw.width/2, pos.y + size.height/2 - sizeDraw.height/2)
+ break
+ case Align.Right:
+ draw.setPositionPx(pos.x + size.width - (sizeDraw.width + m_margin), pos.y + size.height/2 - sizeDraw.height/2)
+ break
+ }
+ }
+
+ function setVisible(bool)
+ {
+ base.setVisible(bool)
+ draw.setVisible(bool)
+ }
+
+ function destroy()
+ {
+ base.destroy()
+ draw.destroy()
+ }
+
+ function setPosition(x, y)
+ {
+ setPositionPx(nax(x), nay(y))
+ }
+
+ function setPositionPx(x, y)
+ {
+ base.setPositionPx(x, y)
+ alignText()
+ }
+
+ function setAlpha(alpha)
+ {
+ draw.setAlpha(alpha)
+ base.setAlpha(alpha)
+ }
+
+ function setText(text)
+ {
+ m_text = text
+
+ if(!m_active && m_text == "")
+ {
+ draw.setText(m_placeholder)
+ return
+ }
+
+ if(m_active)
+ {
+ if(m_type == Input.Password)
+ draw.setText(cutText(hash(m_text) + selector))
+ else
+ draw.setText(cutText(m_text + selector))
+ }
+ else
+ {
+ if(m_type == Input.Password)
+ draw.setText(cutText(hash(m_text)))
+ else
+ draw.setText(cutText(m_text))
+ }
+
+ alignText()
+ }
+
+ function getText()
+ {
+ return m_text
+ }
+
+ function setDisabled(disable)
+ {
+ setActivity(false)
+ base.setDisabled(disable)
+ }
+
+ function setActivity(status)
+ {
+ enableKeys(!status)
+
+ if(m_active == status)
+ return
+
+ m_active = status
+
+ setText(m_text)
+ }
+
+ static function cutText(text)
+ {
+ local size = base.getSizePx()
+ local finishText = ""
+ textSetFont(draw.getFont())
+ for (local i = text.len(); i > 0; i--)
+ {
+ local char = text.slice(i-1, i);
+ if(textWidthPx(finishText + char) < size.width - (2*m_margin))
+ finishText = char + finishText
+ else
+ return finishText
+ }
+ return finishText
+ }
+
+ static function hash(text)
+ {
+ local endText = ""
+ for(local i = 0; i < text.len(); i++)
+ endText += "#"
+
+ return endText
+ }
+
+ function removeLetter()
+ {
+ if(m_text.len() < 1)
+ return
+
+ if(!base.getDisabled())
+ callEvent("GUI.onInputInsertLetter", this, m_text.slice(m_text.len()-1))
+
+ m_text = m_text.slice(0, m_text.len()-1)
+
+ if(m_type == Input.Password)
+ draw.setText(cutText(hash(m_text) + selector))
+ else
+ draw.setText(cutText(m_text + selector))
+ }
+
+ function addLetter(key)
+ {
+ if(m_text.len() > maxLetters)
+ return
+
+ local letter = getKeyLetter(key)
+ if(!letter)
+ return
+
+ if(m_type == Input.Numbers)
+ {
+ if(letter == "0" || letter == "1" || letter == "2" || letter == "3" || letter == "4"
+ || letter == "5" || letter == "6" || letter == "7" || letter == "8" || letter == "9" || letter == "0")
+ m_text += letter
+ }
+ else
+ m_text += letter
+
+ if(m_type == Input.Password)
+ draw.setText(cutText(hash(m_text)) + selector)
+ else
+ draw.setText(cutText(m_text + selector))
+
+ if(!base.getDisabled())
+ callEvent("GUI.onInputRemoveLetter", this, letter)
+ }
+
+ static function keyHandler(key)
+ {
+ foreach(obj in GUI.Input.InputsList)
+ {
+ if(obj.m_active)
+ {
+ if(key == KEY_BACK)
+ obj.removeLetter()
+ else
+ obj.addLetter(key)
+
+ obj.alignText()
+ }
+ }
+ }
+
+ static function clickHandler(btn)
+ {
+ if(btn == MOUSE_LMB)
+ {
+ foreach(obj in GUI.Input.InputsList)
+ {
+ if(!obj.getDisabled())
+ {
+ if(obj.isMouseAt())
+ {
+ obj.setActivity(true)
+ callEvent("GUI.onInputActive", obj)
+ }
+ else
+ {
+ if(obj.m_active)
+ {
+ obj.setActivity(false)
+ callEvent("GUI.onInputDeactive", obj)
+ }
+ }
+
+ obj.alignText()
+ }
+ }
+ }
+ }
+}
+
+addEventHandler("onKey", GUI.Input.keyHandler)
+addEventHandler("onMouseClick", GUI.Input.clickHandler)
diff --git a/lib/gui-framework/elements/multidraw.nut b/lib/gui-framework/elements/multidraw.nut
new file mode 100644
index 0000000..7ed0449
--- /dev/null
+++ b/lib/gui-framework/elements/multidraw.nut
@@ -0,0 +1,235 @@
+class GUI.MultiDraw
+{
+#private:
+ m_visible = false
+
+ m_positionPx = null
+
+ m_letterSpacingPx = 0
+ m_lineSizePx = null
+
+ m_font = "FONT_OLD_10_WHITE_HI.TGA"
+
+ m_color = null
+ m_alpha = 255
+
+#public:
+ lines = null
+
+ constructor(x, y)
+ {
+ lines = []
+
+ m_positionPx = {x = nax(x), y = nay(y)}
+ m_color = {r = 255, g = 255, b = 255}
+ }
+
+ function destroy()
+ {
+ foreach (line in lines)
+ line.destroy()
+ }
+
+ function addLine(text, position = null)
+ {
+ if (position == null)
+ position = lines.len()
+
+ local offset = 0
+
+ if (position > 0)
+ offset = lines[0].getLineSize() * position
+
+ local line = GUI.Draw(anx(m_positionPx.x), any(m_positionPx.y) + offset, text)
+ line.setFont(m_font)
+
+ lines.insert(position, line)
+
+ if (position != lines.len() - 1)
+ setPositionPx(m_positionPx.x, m_positionPx.y)
+ }
+
+ function removeLine(position = null)
+ {
+ if (position == null)
+ position = lines.len() - 1
+
+ lines.remove(position)
+
+ setPositionPx(m_positionPx.x, m_positionPx.y)
+ }
+
+ function getPositionPx()
+ {
+ return m_positionPx
+ }
+
+ function setPositionPx(x, y)
+ {
+ m_positionPx.x = x
+ m_positionPx.y = y
+
+ foreach (line in lines)
+ {
+ line.setPositionPx(x, y)
+ y += getLineSizePx()
+ }
+ }
+
+ function getPosition()
+ {
+ return {x = anx(m_positionPx.x), y = any(m_positionPx.y)}
+ }
+
+ function setPosition(x, y)
+ {
+ setPositionPx(nax(x), nay(y))
+ }
+
+ function getSizePx()
+ {
+ local maxWidth = 0
+ local lineHeight = 0
+
+ foreach (line in lines)
+ {
+ local lineSize = line.getSize()
+
+ if (lineSize.width > maxWidth)
+ maxWidth = lineSize.width
+ }
+
+ if (0 in lines)
+ lineHeight = lines[0].height
+
+ return {width = maxWidth, height = lines.len() * lineHeight}
+ }
+
+ function getSize()
+ {
+ local size = getSizePx()
+ return {width = anx(size.width), height = any(size.height)}
+ }
+
+ function getLetterSpacingPx()
+ {
+ return m_letterSpacingPx
+ }
+
+ function setLetterSpacingPx(spacing)
+ {
+ m_letterSpacingPx = spacing
+
+ foreach (line in lines)
+ line.setLetterSpacingPx(m_letterSpacingPx)
+ }
+
+ function getLetterSpacing()
+ {
+ return nax(m_letterSpacingPx)
+ }
+
+ function setLetterSpacing(spacing)
+ {
+ setLetterSpacingPx(nax(spacing))
+ }
+
+ function getLineSizePx()
+ {
+ if (m_lineSizePx)
+ return m_lineSizePx
+
+ if (0 in lines)
+ return lines[0].getLineSizePx()
+
+ return null
+ }
+
+ function setLineSizePx(lineSize)
+ {
+ m_lineSizePx = lineSize
+ setPositionPx(m_positionPx.x, m_positionPx.y)
+ }
+
+ function getLineSize()
+ {
+ return any(getLineSizePx())
+ }
+
+ function setLineSize(lineSize)
+ {
+ setLineSizePx(any(lineSize))
+ }
+
+ function top()
+ {
+ foreach (line in lines)
+ line.top()
+ }
+
+ function getVisible()
+ {
+ return m_visible
+ }
+
+ function setVisible(visible)
+ {
+ m_visible = visible
+
+ foreach (line in lines)
+ line.setVisible(visible)
+ }
+
+ function getFont()
+ {
+ return m_font
+ }
+
+ function setFont(font)
+ {
+ m_font = font
+
+ foreach (line in lines)
+ line.setFont(font)
+
+ setPositionPx(m_positionPx.x, m_positionPx.y)
+ }
+
+ function getColor()
+ {
+ return m_color
+ }
+
+ function setColor(r, g, b, beginLine = 0, endLine = -1)
+ {
+ if (endLine == -1)
+ {
+ m_color.r = r
+ m_color.g = g
+ m_color.b = b
+
+ endLine = lines.len() - 1
+ }
+
+ for (local i = beginLine; i <= endLine; ++i)
+ lines[i].setColor(r, g, b)
+ }
+
+ function getAlpha()
+ {
+ return m_alpha
+ }
+
+ function setAlpha(alpha, beginLine = 0, endLine = -1)
+ {
+ if (endLine == -1)
+ {
+ m_alpha = alpha
+
+ endLine = lines.len() - 1
+ }
+
+ for (local i = beginLine; i <= endLine; ++i)
+ lines[i].setAlpha(alpha)
+ }
+}
diff --git a/lib/gui-framework/elements/radiobutton.nut b/lib/gui-framework/elements/radiobutton.nut
new file mode 100644
index 0000000..de334a5
--- /dev/null
+++ b/lib/gui-framework/elements/radiobutton.nut
@@ -0,0 +1,62 @@
+class GUI.RadioButton extends GUI.CheckBox
+{
+#private:
+ m_group = null
+
+#public:
+ static activeRadio = {}
+
+ constructor(x, y, width, height, file, selector, group = null, window = null)
+ {
+ base.constructor(x, y, width, height, file, selector, window)
+
+ if (group)
+ setGroup(group)
+
+ enableDeselection(false)
+ }
+
+ function destroy()
+ {
+ if (activeRadio[m_group] == this)
+ activeRadio[m_group] = null
+
+ base.destroy()
+ }
+
+ function getGroup()
+ {
+ return m_group
+ }
+
+ function setGroup(group)
+ {
+ if (m_group != null)
+ delete activeRadio[m_group]
+
+ m_group = group
+
+ if (group != null)
+ {
+ if (!(group in activeRadio))
+ activeRadio[group] <- null
+ }
+ }
+
+ function setChecked(checked)
+ {
+ if (m_group != null && checked)
+ {
+ if (this == GUI.RadioButton.activeRadio[m_group])
+ return
+
+ if (GUI.RadioButton.activeRadio[m_group] != null)
+ GUI.RadioButton.activeRadio[m_group].setChecked(false)
+
+ GUI.RadioButton.activeRadio[m_group] = this
+ base.setChecked(checked)
+ }
+ else
+ base.setChecked(checked)
+ }
+}
diff --git a/lib/gui-framework/elements/range.nut b/lib/gui-framework/elements/range.nut
new file mode 100644
index 0000000..a968ffc
--- /dev/null
+++ b/lib/gui-framework/elements/range.nut
@@ -0,0 +1,324 @@
+// This script was made with a help of Calysto Canem
+
+addEvent("GUI.onChange")
+
+local activeRange = null
+
+class GUI.Range extends classes(GUI.Texture, GUI.Orientation, GUI.Margin)
+{
+#private:
+ m_step = 1
+ m_value = 0
+ m_minimum = 0
+ m_maximum = 100
+
+#public:
+ indicator = null
+
+ constructor(x, y, width, height, file, indicatorFile, orientation = Orientation.Horizontal, window = null)
+ {
+ local indicatorWidth
+ local indicatorHeight
+
+ if (orientation == Orientation.Horizontal)
+ {
+ indicatorWidth = anx(RANGE_INDICATOR_SIZE)
+ indicatorHeight = height
+ }
+ else if (orientation == Orientation.Vertical)
+ {
+ indicatorWidth = width
+ indicatorHeight = any(RANGE_INDICATOR_SIZE)
+ }
+
+ indicator = GUI.Texture(x, y, indicatorWidth, indicatorHeight, indicatorFile)
+ indicator.parent = this
+
+ GUI.Orientation.setOrientation.call(this, orientation)
+ GUI.Margin.constructor.call(this)
+
+ base.constructor(x, y, width, height, file, window)
+ indicator.top()
+ }
+
+ function destroy()
+ {
+ if (activeRange == this)
+ activeRange = null
+
+ indicator = indicator.destroy()
+ base.destroy()
+ }
+
+ function getPercentage()
+ {
+ return fabs(m_value - m_minimum) / fabs(m_maximum - m_minimum)
+ }
+
+ function getValue()
+ {
+ return m_value
+ }
+
+ function setValue(value)
+ {
+ local min = m_minimum, max = m_maximum
+
+ if (min > max)
+ {
+ min = m_maximum
+ max = m_minimum
+ }
+
+ if (value < min)
+ value = min
+ else if (value > max)
+ value = max
+
+ local oldValue = m_value
+ m_value = value
+
+ local position = base.getPositionPx()
+ local size = base.getSizePx()
+
+ local indicatorPosition = indicator.getPositionPx()
+ local indicatorSize = indicator.getSizePx()
+
+ position.x += m_marginPx.left
+ position.y += m_marginPx.top
+
+ if (m_orientation == Orientation.Horizontal)
+ {
+ size.width -= indicatorSize.width + m_marginPx.left + m_marginPx.right
+ indicator.setPositionPx(position.x + size.width * getPercentage(), position.y)
+ }
+ else if (m_orientation == Orientation.Vertical)
+ {
+ size.height -= indicatorSize.height + m_marginPx.top + m_marginPx.bottom
+ indicator.setPositionPx(position.x, position.y + size.height * getPercentage())
+ }
+
+ if (value != oldValue)
+ callEvent("GUI.onChange", this)
+ }
+
+ function getMinimum()
+ {
+ return m_minimum
+ }
+
+ function setMinimum(minimum)
+ {
+ m_minimum = minimum
+ setValue(m_value)
+ }
+
+ function getMaximum()
+ {
+ return m_maximum
+ }
+
+ function setMaximum(maximum)
+ {
+ m_maximum = maximum
+ setValue(m_value)
+ }
+
+ function getStep()
+ {
+ return m_step
+ }
+
+ function setStep(step)
+ {
+ m_step = step
+ }
+
+ function changeSection(cursorPositionX, cursorPositionY)
+ {
+ local position = base.getPositionPx()
+ local size = base.getSizePx()
+
+ local indicatorSize = indicator.getSizePx()
+
+ // calculating distance and make it positive number
+ local distance = m_maximum - m_minimum
+
+ if (distance < 0)
+ distance = -distance
+
+ // normalizing distance
+ distance -= distance % m_step
+
+ // setting margin, calculating percentage cursor location on slider, center the percentageLocation
+ local percentageLocation
+
+ position.x += m_marginPx.left
+ position.y += m_marginPx.top
+
+ if (m_orientation == Orientation.Horizontal)
+ {
+ size.width -= m_marginPx.left + m_marginPx.right
+
+ percentageLocation = (cursorPositionX - position.x).tofloat() / (size.width - indicatorSize.width)
+ percentageLocation -= (indicatorSize.width / 2).tofloat() / size.width
+ }
+ else
+ {
+ size.height -= m_marginPx.top + m_marginPx.bottom
+
+ percentageLocation = (cursorPositionY - position.y).tofloat() / (size.height - indicatorSize.height)
+ percentageLocation -= (indicatorSize.height / 2).tofloat() / size.height
+ }
+
+ // inverting percentage if max < min, calculating newValue, adding distance between ranges
+ local isMaxLessThanMin = (m_maximum < m_minimum)
+
+ if (isMaxLessThanMin)
+ percentageLocation = 1.0 - percentageLocation
+
+ local newValue = percentageLocation * distance
+
+ if (isMaxLessThanMin)
+ newValue += (m_minimum - distance)
+ else
+ newValue += (m_maximum - distance)
+
+ // normalizing newValue
+ newValue -= newValue % m_step
+
+ setValue(newValue)
+ }
+
+ function setAlpha(alpha)
+ {
+ base.setAlpha(alpha)
+ indicator.setAlpha(alpha)
+ }
+
+ function top()
+ {
+ base.top()
+ indicator.top()
+ }
+
+ function setVisible(visible)
+ {
+ base.setVisible(visible)
+ indicator.setVisible(visible)
+ }
+
+ function setPositionPx(x, y)
+ {
+ local position = base.getPositionPx()
+ local indicatorPosition = indicator.getPositionPx()
+
+ base.setPositionPx(x, y)
+ indicator.setPositionPx(x + (indicatorPosition.x - position.x), y + (indicatorPosition.y - position.y))
+ }
+
+ function setPosition(x, y)
+ {
+ setPositionPx(nax(x), nay(y))
+ }
+
+ function setSizePx(width, height)
+ {
+ base.setSizePx(width, height)
+ setValue(m_value)
+ }
+
+ function setSize(width, height)
+ {
+ setSizePx(nax(width), nay(height))
+ }
+
+ function setMarginPx(top, right, bottom, left)
+ {
+ GUI.Margin.setMarginPx.call(this, top, right, bottom, left)
+
+ local size = getSizePx()
+ local indicatorSize = indicator.getSizePx()
+
+ if (m_orientation == Orientation.Horizontal)
+ {
+ size.height -= m_marginPx.bottom
+ indicator.setSizePx(indicatorSize.width, size.height)
+ }
+ else if (m_orientation == Orientation.Vertical)
+ {
+ size.width -= m_marginPx.right
+ indicator.setSizePx(size.width, indicatorSize.height)
+ }
+
+ setValue(m_value)
+ }
+
+ function setMargin(top, right, bottom, left)
+ {
+ setMarginPx(top, right, bottom, left)
+ }
+
+ static function getActiveElement()
+ {
+ return activeRange
+ }
+
+ static function setActiveElement(element)
+ {
+ activeRange = element
+ }
+
+ static function onMouseDown(self, button)
+ {
+ if (button != MOUSE_LMB)
+ return
+
+ if (activeRange)
+ return
+
+ if (self instanceof GUI.Range)
+ {
+ if (self.indicator.isMouseAt())
+ return
+
+ local cursorPosition = getCursorPositionPx()
+
+ self.changeSection(cursorPosition.x, cursorPositionY)
+ activeRange = self
+ }
+ else if (self instanceof GUI.Texture)
+ {
+ if (!(self.parent instanceof GUI.Range))
+ return
+
+ if (self != self.parent.indicator)
+ return
+
+ activeRange = self.parent
+ }
+ }
+
+ static function onMouseRelease(button)
+ {
+ if (button != MOUSE_LMB)
+ return
+
+ if (!activeRange)
+ return
+
+ activeRange = null
+ }
+
+ static function onMouseMove(newCursorX, newCursorY, oldCursorX, oldCursorY)
+ {
+ if (!activeRange)
+ return
+
+ activeRange.changeSection(newCursorX, newCursorY)
+ }
+}
+
+addEventHandler("GUI.onMouseDown", GUI.Range.onMouseDown)
+addEventHandler("onMouseRelease", GUI.Range.onMouseRelease)
+addEventHandler("onMouseMove", GUI.Range.onMouseMove)
diff --git a/lib/gui-framework/elements/scrollbar.nut b/lib/gui-framework/elements/scrollbar.nut
new file mode 100644
index 0000000..e489151
--- /dev/null
+++ b/lib/gui-framework/elements/scrollbar.nut
@@ -0,0 +1,324 @@
+local activeHorizonalScrollBar = null
+local activeVerticalScrollBar = null
+
+local activeScrollBarButton = null
+local activeScrollBarButtonDirection = 0
+local scrollBarNextTick = getTickCount()
+
+local activeScrollBarClickPosition = null
+
+class GUI.ScrollBar extends GUI.Range
+{
+#public:
+ decreaseButton = null
+ increaseButton = null
+
+ constructor(x, y, width, height, file, sliderFile, decreaseButtonFile, increaseButtonFile, orientation = Orientation.Horizontal, window = null)
+ {
+ if (orientation == Orientation.Horizontal)
+ {
+ local buttonSize = anx(SCROLLBAR_BUTTON_SIZE)
+
+ decreaseButton = GUI.Button(x, y, buttonSize, height, decreaseButtonFile)
+ increaseButton = GUI.Button(x + width - buttonSize, y, buttonSize, height, increaseButtonFile)
+
+ x += buttonSize
+ width -= buttonSize * 2
+ }
+ else if (orientation == Orientation.Vertical)
+ {
+ local buttonSize = any(SCROLLBAR_BUTTON_SIZE)
+
+ decreaseButton = GUI.Button(x, y, width, buttonSize, decreaseButtonFile)
+ increaseButton = GUI.Button(x, y + height - buttonSize, width, buttonSize, increaseButtonFile)
+
+ y += buttonSize
+ height -= buttonSize * 2
+ }
+
+ decreaseButton.parent = this
+ increaseButton.parent = this
+
+ base.constructor(x, y, width, height, file, sliderFile, orientation, window)
+ }
+
+ function destroy()
+ {
+ if (activeHorizonalScrollBar == this)
+ activeHorizonalScrollBar = null
+ else if (activeVerticalScrollBar == this)
+ activeVerticalScrollBar = null
+
+ if (activeScrollBarButton == decreaseButton || activeScrollBarButton == increaseButton)
+ activeScrollBarButton = null
+
+ increaseButton = increaseButton.destroy()
+ decreaseButton = decreaseButton.destroy()
+ base.destroy()
+ }
+
+ function changeSection(cursorPositionX, cursorPositionY)
+ {
+ local isHorizontal = (m_orientation == Orientation.Horizontal)
+
+ local position = getPositionPx()
+ local cursorDistance = (isHorizontal) ? cursorPositionY - position.y : cursorPositionX - position.x
+
+ if (cursorDistance < 0)
+ cursorDistance = -cursorDistance
+
+ if (cursorDistance <= SCROLLBAR_DRAG_DISTANCE)
+ base.changeSection(cursorPositionX, cursorPositionY)
+ else
+ {
+ if (isHorizontal)
+ base.changeSection(activeScrollBarClickPosition, cursorPositionY)
+ else
+ base.changeSection(cursorPositionX, activeScrollBarClickPosition)
+ }
+ }
+
+ function setAlpha(alpha)
+ {
+ increaseButton.setAlpha(alpha)
+ decreaseButton.setAlpha(alpha)
+ base.setAlpha(alpha)
+ }
+
+ function top()
+ {
+ increaseButton.top()
+ decreaseButton.top()
+ base.top()
+ }
+
+ function getActive()
+ {
+ if (m_orientation == Orientation.Horizontal)
+ return this == activeHorizonalScrollBar
+ else if (m_orientation == Orientation.Vertical)
+ return this == activeVerticalScrollBar
+ }
+
+ function setActive()
+ {
+ if (m_orientation == Orientation.Horizontal)
+ activeHorizonalScrollBar = this
+ else if (m_orientation == Orientation.Vertical)
+ activeVerticalScrollBar = this
+ }
+
+ function setVisible(visible)
+ {
+ base.setVisible(visible)
+
+ decreaseButton.setVisible(visible)
+ increaseButton.setVisible(visible)
+
+ if (visible)
+ {
+ if (!activeHorizonalScrollBar && m_orientation == Orientation.Horizontal)
+ activeHorizonalScrollBar = this
+ else if (!activeVerticalScrollBar && m_orientation == Orientation.Vertical)
+ activeVerticalScrollBar = this
+ }
+ else
+ {
+ if (activeHorizonalScrollBar == this)
+ activeHorizonalScrollBar = null
+ else if (activeVerticalScrollBar == this)
+ activeVerticalScrollBar = null
+ }
+ }
+
+ function getPositionPx()
+ {
+ return decreaseButton.getPositionPx()
+ }
+
+ function getPosition()
+ {
+ return decreaseButton.getPosition()
+ }
+
+ function setPositionPx(x, y)
+ {
+ local buttonSize = decreaseButton.getSizePx()
+ local size = base.getSizePx()
+
+ if (m_orientation == Orientation.Horizontal)
+ {
+ decreaseButton.setPositionPx(x, y)
+ increaseButton.setPositionPx(x + size.width + buttonSize.width, y)
+
+ base.setPositionPx(x + buttonSize.width, y)
+ }
+ else if (m_orientation == Orientation.Vertical)
+ {
+ decreaseButton.setPositionPx(x, y)
+ increaseButton.setPositionPx(x, y + size.height + buttonSize.height)
+
+ base.setPositionPx(x, y + buttonSize.height)
+ }
+ }
+
+ function setPosition(x, y)
+ {
+ setPositionPx(nax(x), nay(y))
+ }
+
+ function getSizePx()
+ {
+ local size = base.getSizePx()
+ local buttonSize = decreaseButton.getSizePx()
+
+ if (m_orientation == Orientation.Horizontal)
+ size.width += buttonSize.width * 2
+ else if (m_orientation == Orientation.Vertical)
+ size.height += buttonSize.height * 2
+
+ return size
+ }
+
+ function getSize()
+ {
+ local sizePx = getSizePx()
+ return {width = anx(sizePx.width), height = any(sizePx.height)}
+ }
+
+ function setSizePx(width, height)
+ {
+ local position = getPositionPx()
+ local buttonSize = decreaseButton.getSizePx()
+
+ if (m_orientation == Orientation.Horizontal)
+ increaseButton.setPositionPx(position.x + width + buttonSize.width, position.y)
+ else if (m_orientation == Orientation.Vertical)
+ increaseButton.setPositionPx(position.x, position.y + height + buttonSize.height)
+
+ base.setSizePx(width, height)
+ }
+
+ function setSize(width, height)
+ {
+ setSizePx(nax(width), nay(height))
+ }
+
+ static function onMouseDown(self, btn)
+ {
+ if (btn != MOUSE_LMB)
+ return
+
+ local activeElement = GUI.Range.getActiveElement()
+
+ if (activeElement && activeScrollBarClickPosition == null)
+ {
+ local cursorPosition = getCursorPositionPx()
+ local isHorizontal = (activeElement.m_orientation == Orientation.Horizontal)
+
+ if (activeScrollBarClickPosition == null)
+ activeScrollBarClickPosition = (isHorizontal) ? cursorPosition.x : cursorPosition.y
+ }
+
+ if (!(self.parent instanceof GUI.ScrollBar))
+ return
+
+ local scrollBar = self.parent
+
+ if (self == scrollBar.decreaseButton)
+ {
+ activeScrollBarButton = scrollBar.decreaseButton
+ activeScrollBarButtonDirection = -1
+ scrollBarNextTick = getTickCount()
+ }
+ else if (self == scrollBar.increaseButton)
+ {
+ activeScrollBarButton = scrollBar.increaseButton
+ activeScrollBarButtonDirection = 1
+ scrollBarNextTick = getTickCount()
+ }
+ }
+
+ static function onMouseRelease(btn)
+ {
+ if (btn != MOUSE_LMB)
+ return
+
+ activeScrollBarButton = null
+ activeScrollBarClickPosition = null
+ }
+
+ static function onRender()
+ {
+ if (!activeScrollBarButton)
+ return
+
+ local now = getTickCount()
+
+ if (scrollBarNextTick > now)
+ return
+
+ scrollBarNextTick = scrollBarNextTick + 100
+
+ if (!activeScrollBarButton.isMouseAt())
+ return
+
+ local scrollBar = activeScrollBarButton.parent
+ scrollBar.setValue(scrollBar.getValue() + activeScrollBarButtonDirection * scrollBar.m_step)
+ }
+
+
+ static function onKey(key)
+ {
+ local horizontalKey = 0
+ local verticalKey = 0
+
+ switch (key)
+ {
+ case KEY_LEFT:
+ horizontalKey = -1
+ break
+
+ case KEY_RIGHT:
+ horizontalKey = 1
+ break
+
+ case KEY_UP:
+ verticalKey = -1
+ break
+
+ case KEY_DOWN:
+ verticalKey = 1
+ break
+ }
+
+ if (horizontalKey)
+ {
+ if (!activeHorizonalScrollBar || activeHorizonalScrollBar.getDisabled())
+ return
+
+ activeHorizonalScrollBar.setValue(activeHorizonalScrollBar.getValue() + activeHorizonalScrollBar.m_step * horizontalKey)
+ }
+ else if (verticalKey)
+ {
+ if (!activeVerticalScrollBar || activeVerticalScrollBar.getDisabled())
+ return
+
+ activeVerticalScrollBar.setValue(activeVerticalScrollBar.getValue() + activeVerticalScrollBar.m_step * verticalKey)
+ }
+ }
+
+ static function onMouseWheel(direction)
+ {
+ if (!activeVerticalScrollBar || activeVerticalScrollBar.getDisabled())
+ return
+
+ activeVerticalScrollBar.setValue(activeVerticalScrollBar.getValue() - direction * activeVerticalScrollBar.m_step)
+ }
+}
+addEventHandler("GUI.onMouseDown", GUI.ScrollBar.onMouseDown)
+addEventHandler("onMouseRelease", GUI.ScrollBar.onMouseRelease)
+addEventHandler("onRender", GUI.ScrollBar.onRender)
+addEventHandler("GUI.onMouseDown", GUI.ScrollBar.onMouseDown)
+addEventHandler("onKey", GUI.ScrollBar.onKey)
+addEventHandler("onMouseWheel", GUI.ScrollBar.onMouseWheel)
diff --git a/lib/gui-framework/elements/slider.nut b/lib/gui-framework/elements/slider.nut
new file mode 100644
index 0000000..2777755
--- /dev/null
+++ b/lib/gui-framework/elements/slider.nut
@@ -0,0 +1,121 @@
+class GUI.Slider extends GUI.Range
+{
+#public:
+ bar = null
+
+ constructor(x, y, width, height, marginX, marginY, background, progress, indicatorFile, orientation = Orientation.Horizontal, alignment = Align.Left, node = null)
+ {
+ bar = GUI.Bar(x, y, width, height, marginX, marginY, "", progress, orientation, alignment)
+ base.constructor(x, y, width, height, background, indicatorFile, orientation, node)
+
+ if (alignment == Align.Right)
+ swapMinMax()
+
+ bar.top()
+ indicator.top()
+ }
+
+ function destroy()
+ {
+ bar = bar.destroy()
+ base.destroy()
+ }
+
+ function swapMinMax()
+ {
+ local minimum = getMinimum()
+ local maximum = getMaximum()
+
+ local value = getValue()
+
+ base.setMaximum(minimum)
+ base.setMinimum(maximum)
+
+ setValue(value)
+ }
+
+ function setMinimum(minimum)
+ {
+ base.setMinimum(minimum)
+ bar.setMinimum(minimum)
+ }
+
+ function setMaximum(maximum)
+ {
+ base.setMaximum(maximum)
+ bar.setMaximum(maximum)
+ }
+
+ function setValue(value)
+ {
+ base.setValue(value)
+ bar.setValue(value)
+ }
+
+ function getAlignment()
+ {
+ return bar.getAlignment()
+ }
+
+ function setAlignment(alignment)
+ {
+ if (alignment == getAlignment())
+ return
+
+ swapMinMax()
+ bar.setAlignment(alignment)
+ }
+
+ function setMarginPx(top, right, bottom, left)
+ {
+ base.setMarginPx(top, right, bottom, left)
+ bar.setMarginPx(top, right, bottom, left)
+ }
+
+ function setMargin(top, right, bottom, left)
+ {
+ setMarginPx(nay(top), nax(right), nay(bottom), nax(left))
+ }
+
+ function setVisible(visible)
+ {
+ base.setVisible(visible)
+ bar.setVisible(visible)
+ }
+
+ function setAlpha(alpha)
+ {
+ base.setAlpha(alpha)
+ bar.setAlpha(alpha)
+ }
+
+ function setPosition(x, y)
+ {
+ setPositionPx(nax(x), nay(y))
+ }
+
+ function setPositionPx(x, y)
+ {
+ base.setPositionPx(x, y)
+ bar.setPositionPx(x, y)
+ }
+
+ function setSize(width, height)
+ {
+ setSizePx(nax(width), nay(height))
+ }
+
+ function setSizePx(width, height)
+ {
+ base.setSizePx(width, height)
+ bar.setSizePx(width, height)
+ }
+
+ function top()
+ {
+ base.top()
+
+ bar.top()
+ indicator.top()
+ }
+}
diff --git a/lib/gui-framework/elements/tabpanel.nut b/lib/gui-framework/elements/tabpanel.nut
new file mode 100644
index 0000000..7c59c74
--- /dev/null
+++ b/lib/gui-framework/elements/tabpanel.nut
@@ -0,0 +1,406 @@
+addEvent("GUI.onSwitch")
+
+local movableTab = null
+local cursorOffset = 0
+
+class GUI.Tab extends GUI.Button
+{
+#private:
+ m_title = ""
+
+#public:
+ id = -1
+
+ constructor(parent, id, file, text)
+ {
+ this.parent = parent
+ this.id = id
+
+ base.constructor(0, 0, 0, 0, file, text)
+
+ m_title = text
+ }
+
+ function destroy()
+ {
+ if (this == movableTab)
+ movableTab = null
+
+ base.destroy()
+ }
+
+ function setText(text)
+ {
+ if (draw)
+ base.setText(text)
+
+ m_title = text
+ }
+
+ static function onMouseDown(self, btn)
+ {
+ if (btn != MOUSE_LMB)
+ return
+
+ if (!(self instanceof GUI.Tab))
+ return
+
+ local panel = self.parent
+
+ if (!panel.m_tabsMovementEnabled)
+ return
+
+ local position = self.getPositionPx()
+ local cursorPosition = getCursorPositionPx()
+
+ if (panel.m_orientation == Orientation.Horizontal)
+ cursorOffset = cursorPosition.x - position.x
+ else if (panel.m_orientation == Orientation.Vertical)
+ cursorOffset = cursorPosition.y - position.y
+
+ self.top()
+
+ panel.setActiveTab(self.id)
+ movableTab = self
+ }
+
+ static function onMouseRelease(button)
+ {
+ if (button != MOUSE_LMB)
+ return
+
+ if (!movableTab)
+ return
+
+ local panel = movableTab.parent
+
+ local position = panel.getPositionPx()
+ local margin = panel.getMarginPx()
+
+ position.x += margin.left
+ position.y += margin.top
+
+ for (local i = 0; i < movableTab.id; ++i)
+ {
+ local size = panel.tabs[i].getSizePx()
+
+ if (panel.m_orientation == Orientation.Horizontal)
+ position.x += size.width
+ else if (panel.m_orientation == Orientation.Vertical)
+ position.y += size.height
+ }
+
+ movableTab.setPositionPx(position.x, position.y)
+ movableTab = null
+ }
+
+ static function onMouseMove(newCursorX, newCursorY, oldCursorX, oldCursorY)
+ {
+ if (!isMouseBtnPressed(MOUSE_LMB))
+ return
+
+ if (!movableTab)
+ return
+
+ local tabPosition = movableTab.getPositionPx()
+ local tabSize = movableTab.getSizePx()
+
+ local panel = movableTab.parent
+ local tabsCount = panel.tabs.len()
+
+ local dimension, size
+ local minimumPanelRange, maximumPanelRange
+ local cursorMovingDirection
+
+ // Moving tab, keeping tab in panel range,
+ //determinating the cursor movement direction
+
+ if (panel.m_orientation == Orientation.Horizontal)
+ {
+ dimension = "x"
+ size = "width"
+
+ tabPosition.x = newCursorX - cursorOffset
+ minimumPanelRange = maximumPanelRange = panel.getPositionPx().x
+
+ cursorMovingDirection = (newCursorX - oldCursorX) < 0 ? -1 : 1
+ }
+ else if (panel.m_orientation == Orientation.Vertical)
+ {
+ dimension = "y"
+ size = "height"
+
+ tabPosition.y = newCursorY -cursorOffset
+ minimumPanelRange = maximumPanelRange = panel.getPositionPx().y
+
+ cursorMovingDirection = (newCursorY - oldCursorY) < 0 ? -1 : 1
+ }
+
+ for (local i = 0; i < tabsCount - 1; ++i)
+ maximumPanelRange += panel.tabs[i].getSizePx()[size]
+
+ if (tabPosition[dimension] < minimumPanelRange)
+ tabPosition[dimension] = minimumPanelRange
+ else if (tabPosition[dimension] > maximumPanelRange)
+ tabPosition[dimension] = maximumPanelRange
+
+ // Checking if tab can be swapped,
+ //swapping tab with nearest tab, if our tab is on half way to the nearest tab
+
+ if ((cursorMovingDirection == -1 && movableTab.id > 0)
+ || (cursorMovingDirection == 1 && movableTab.id < tabsCount - 1))
+ {
+ local nearTab = panel.tabs[movableTab.id + cursorMovingDirection]
+ local nearTabPosition = nearTab.getPositionPx()
+ local nearTabSize = nearTab.getSizePx()
+
+ if ((cursorMovingDirection == -1 && tabPosition[dimension] < nearTabPosition[dimension] + nearTabSize[size] / 2)
+ || (cursorMovingDirection == 1 && tabPosition[dimension] >= nearTabPosition[dimension] - nearTabSize[size] / 2))
+ {
+ if (panel.m_orientation == Orientation.Horizontal)
+ nearTab.setPositionPx(nearTabPosition.x + tabSize.width * -cursorMovingDirection, nearTabPosition.y)
+ else
+ nearTab.setPositionPx(nearTabPosition.x, nearTabPosition.y + tabSize.height * -cursorMovingDirection)
+
+ panel.tabs[movableTab.id + cursorMovingDirection] = movableTab
+ panel.tabs[movableTab.id] = nearTab
+
+ nearTab.id -= cursorMovingDirection
+ movableTab.id += cursorMovingDirection
+ }
+ }
+
+ movableTab.setPositionPx(tabPosition.x, tabPosition.y)
+ }
+}
+
+addEventHandler("GUI.onMouseDown", GUI.Tab.onMouseDown)
+addEventHandler("onMouseRelease", GUI.Tab.onMouseRelease)
+addEventHandler("onMouseMove", GUI.Tab.onMouseMove)
+
+class GUI.TabPanel extends classes(GUI.Texture, GUI.Orientation, GUI.Margin)
+{
+#private:
+ m_tabsMovementEnabled = true
+
+ m_font = "FONT_OLD_10_WHITE_HI.TGA"
+
+ m_activeTab = null
+ m_tabSizePx = null
+
+#public:
+ tabs = null
+
+ constructor(x, y, width, height, file, orientation = Orientation.Horizontal, window = null)
+ {
+ tabs = []
+
+ m_tabSizePx = {width = 0, height = 0}
+
+ GUI.Margin.constructor.call(this)
+ GUI.Orientation.setOrientation.call(this, orientation)
+ GUI.Texture.constructor.call(this, x, y, width, height, file, window)
+ }
+
+ function destroy()
+ {
+ m_activeTab = null
+
+ foreach (index, _ in tabs)
+ tabs[index] = tabs[index].destroy()
+
+ GUI.Texture.destroy.call(this)
+ }
+
+ function insertTab(index, file, text)
+ {
+ local tab = GUI.Tab(this, index, file, text)
+
+ if (tab.draw)
+ tab.draw.setFont(m_font)
+
+ tabs.insert(index, tab)
+
+ local tabsCount = tabs.len()
+
+ for (local i = index + 1; i < tabsCount; ++i)
+ ++tabs[i].id
+
+ local size = getSizePx()
+ setSizePx(size.width, size.height)
+
+ if (visible)
+ tab.setVisible(true)
+
+ return tab
+ }
+
+ function addTab(file, text)
+ {
+ return insertTab(tabs.len(), file, text)
+ }
+
+ function removeTab(id)
+ {
+ local tabsCount = tabs.len()
+
+ if (!tabsCount)
+ return
+
+ for (local i = id; i < tabsCount; ++i)
+ --tabs[i].id
+
+ if (m_activeTab == tabs[id])
+ {
+ if (tabsCount == 1)
+ setActiveTab(null)
+ else if (id + 1 < tabsCount)
+ setActiveTab(id + 1)
+ else
+ setActiveTab(id - 1)
+ }
+
+ tabs[id] = tabs[id].destroy()
+ tabs.remove(id)
+
+ local size = getSizePx()
+ setSizePx(size.width, size.height)
+ }
+
+ function setMarginPx(top, right, bottom, left)
+ {
+ GUI.Margin.setMarginPx.call(this, top, right, bottom, left)
+
+ local position = getPositionPx()
+ setPositionPx(position.x, position.y)
+
+ local size = getSizePx()
+ setSizePx(size.width, size.height)
+ }
+
+ function setMargin(top, right, bottom, left)
+ {
+ setMarginPx(nay(top), nax(right), nay(bottom), nax(left))
+ }
+
+ function getActiveTab()
+ {
+ return m_activeTab
+ }
+
+ function setActiveTab(id)
+ {
+ local tab = (id != null) ? tabs[id] : null
+
+ callEvent("GUI.onSwitch", tab, m_activeTab)
+ m_activeTab = tab
+ }
+
+ function getTabsMovement()
+ {
+ return m_tabsMovementEnabled
+ }
+
+ function setTabsMovement(movement)
+ {
+ m_tabsMovementEnabled = movement
+ }
+
+ function setPositionPx(x, y)
+ {
+ GUI.Texture.setPositionPx.call(this, x, y)
+
+ x += m_marginPx.left
+ y += m_marginPx.top
+
+ foreach (tab in tabs)
+ {
+ tab.setPositionPx(x, y)
+
+ if (m_orientation == Orientation.Horizontal)
+ x += m_tabSizePx.width
+ else if (m_orientation == Orientation.Vertical)
+ y += m_tabSizePx.height
+ }
+ }
+
+ function setPosition(x, y)
+ {
+ setPositionPx(nax(x), nay(y))
+ }
+
+ function setSizePx(width, height)
+ {
+ GUI.Texture.setSizePx.call(this, width, height)
+
+ local tabsCount = tabs.len()
+
+ if (!tabsCount)
+ return
+
+ width -= m_marginPx.left + m_marginPx.right
+ height -= m_marginPx.top + m_marginPx.bottom
+
+ if (m_orientation == Orientation.Horizontal)
+ {
+ m_tabSizePx.width = width / tabsCount
+ m_tabSizePx.height = height
+ }
+ else if (m_orientation == Orientation.Vertical)
+ {
+ m_tabSizePx.width = width
+ m_tabSizePx.height = height / tabsCount
+ }
+
+ foreach (tab in tabs)
+ tab.setSizePx(m_tabSizePx.width, m_tabSizePx.height)
+
+ local position = getPositionPx()
+ setPositionPx(position.x, position.y)
+ }
+
+ function setSize(width, height)
+ {
+ setSizePx(nax(width), nay(height))
+ }
+
+ function setVisible(visible)
+ {
+ GUI.Texture.setVisible.call(this, visible)
+
+ foreach (tab in tabs)
+ tab.setVisible(visible)
+
+ if (visible)
+ {
+ if (!m_activeTab && (0 in tabs))
+ setActiveTab(0)
+ }
+ else
+ setActiveTab(null)
+ }
+
+ function top()
+ {
+ GUI.Texture.top.call(this)
+
+ foreach (tab in tabs)
+ tab.top()
+ }
+
+ function getFont()
+ {
+ return m_font
+ }
+
+ function setFont(font)
+ {
+ m_font = font
+
+ foreach (tab in tabs)
+ {
+ if (tab.draw)
+ tab.draw.setFont(m_font)
+ }
+ }
+}
diff --git a/lib/gui-framework/elements/texture.nut b/lib/gui-framework/elements/texture.nut
new file mode 100644
index 0000000..ef4f0d9
--- /dev/null
+++ b/lib/gui-framework/elements/texture.nut
@@ -0,0 +1,225 @@
+class GUI.Texture extends classes(Texture, GUI.Base)
+{
+#protected:
+ m_scaling = false
+
+ m_FPS = 0
+
+ m_beginFrame = 0
+ m_endFrame = 0
+ m_direction = 1
+ m_repeat = true
+ m_isPlaying = true
+
+ m_currentFrame = 0
+ m_nextFrameTime = 0
+
+ constructor(x, y, width, height, file, window = null)
+ {
+ GUI.Base.constructor.call(this)
+ Texture.constructor.call(this, x, y, width, height, file)
+
+ m_nextFrameTime = getTickCount()
+
+ if (window)
+ window.insert(this)
+ }
+
+ function top()
+ {
+ GUI.Base.top.call(this)
+ Texture.top.call(this)
+ }
+
+ function setPositionPx(x, y)
+ {
+ base.setPositionPx(x, y)
+ }
+
+ function getVisible()
+ {
+ return visible
+ }
+
+ function setVisible(visible)
+ {
+ base.setVisible(visible)
+ this.visible = visible
+ }
+
+ function getFile()
+ {
+ return file
+ }
+
+ function setFile(file)
+ {
+ this.file = file
+ }
+
+ function getScaling()
+ {
+ return m_scaling
+ }
+
+ function setScaling(scaling)
+ {
+ m_scaling = scaling
+ }
+
+ function getFPS()
+ {
+ return m_FPS
+ }
+
+ function setFPS(FPS)
+ {
+ m_FPS = FPS
+ }
+
+ function getBeginFrame()
+ {
+ return m_beginFrame
+ }
+
+ function setBeginFrame(beginFrame)
+ {
+ m_beginFrame = beginFrame
+ }
+
+ function getEndFrame()
+ {
+ return m_endFrame
+ }
+
+ function setEndFrame(endFrame)
+ {
+ m_endFrame = endFrame
+ }
+
+ function getCurrentFrame()
+ {
+ return m_currentFrame
+ }
+
+ function setCurrentFrame(currentFrame)
+ {
+ if (currentFrame < m_beginFrame)
+ currentFrame = m_beginFrame
+ else if (currentFrame > m_endFrame)
+ currentFrame = m_endFrame
+
+ m_currentFrame = currentFrame
+
+ local baseName = ""
+
+ for (local ch = file.len() - 1; ch > 0; --ch)
+ {
+ if (file[ch] == '_')
+ {
+ baseName = file.slice(0, ch)
+ break
+ }
+ }
+
+ file = baseName+"_A"+currentFrame+".TGA"
+ }
+
+ function getDirection()
+ {
+ return m_direction
+ }
+
+ function setDirection(direction)
+ {
+ if (direction > 1)
+ direction = 1
+ else if (direction < -1)
+ direction = -1
+
+ m_direction = direction
+ }
+
+ function getRepeat()
+ {
+ return m_repeat
+ }
+
+ function setRepeat(repeat)
+ {
+ m_repeat = repeat
+ }
+
+ function isPlaying()
+ {
+ return (m_isPlaying && m_FPS > 0)
+ }
+
+ function play()
+ {
+ m_isPlaying = true
+ }
+
+ function stop()
+ {
+ m_isPlaying = false
+ }
+
+ static function onRender(self)
+ {
+ if (!(self instanceof GUI.Texture))
+ return
+
+ // FPS Animation
+
+ local now = getTickCount()
+
+ if (self.isPlaying())
+ {
+ if (now >= self.m_nextFrameTime)
+ {
+ if (self.m_direction == 1 && self.m_currentFrame < self.m_endFrame
+ || self.m_direction == -1 && self.m_currentFrame > self.m_beginFrame)
+ self.m_currentFrame += self.m_direction
+ else if (self.m_repeat)
+ self.m_currentFrame = (self.m_direction == 1) ? self.m_beginFrame : self.m_endFrame
+
+ local baseName = ""
+
+ for (local ch = self.file.len() - 1; ch > 0; --ch)
+ {
+ if (self.file[ch] == '_')
+ {
+ baseName = self.file.slice(0, ch)
+ break
+ }
+ }
+
+ self.file = baseName+"_A"+self.m_currentFrame+".TGA"
+ self.m_nextFrameTime += 1000 / self.m_FPS
+ }
+ }
+ else
+ self.m_nextFrameTime = now
+ }
+
+ static function onChangeResolution()
+ {
+ local scalingProportion = getResolutionChangedScale()
+
+ foreach (object in base.m_objects)
+ {
+ if (!(object instanceof GUI.Texture))
+ break
+
+ if (!object.m_scaling)
+ continue
+
+ local size = object.getSizePx()
+ object.setSizePx(size.width * scalingProportion.x, size.height * scalingProportion.y)
+ }
+ }
+}
+
+addEventHandler("GUI.onRender", GUI.Texture.onRender)
+addEventHandler("onChangeResolution", GUI.Texture.onChangeResolution)
diff --git a/lib/gui-framework/elements/tooltip.nut b/lib/gui-framework/elements/tooltip.nut
new file mode 100644
index 0000000..da8ac03
--- /dev/null
+++ b/lib/gui-framework/elements/tooltip.nut
@@ -0,0 +1,129 @@
+local activeToolTip = null
+local toolTipInterval = -1
+
+class GUI.ToolTip extends GUI.Button
+{
+#private:
+ m_toolTip = null
+ m_paddingPx = null
+
+#public:
+ draw = null
+
+ constructor(width, height, file, text = null)
+ {
+ m_toolTip = {}
+
+ base.constructor(0, 0, width, height, file, text)
+ base.setDisabled(true)
+
+ if (text)
+ {
+ m_paddingPx = {x = nax(width) * 2, y = nay(height) * 2}
+
+ local size = draw.getSize()
+ setSize(size.width + width, size.height + height)
+ }
+ }
+
+ function getToolTip(object)
+ {
+ if (!(object in m_toolTip))
+ return null
+
+ return m_toolTip[object]
+ }
+
+ function setToolTip(object, text)
+ {
+ object.toolTip = this
+ m_toolTip[object] <- text
+ }
+
+ function getPaddingPx()
+ {
+ return m_paddingPx
+ }
+
+ function setPaddingPx(x, y)
+ {
+ m_paddingPx.x = x
+ m_paddingPx.y = y
+
+ local drawSize = draw.getSizePx()
+ setSizePx(drawSize.width + m_paddingPx.x * 2, drawSize.height + m_paddingPx.y * 2)
+ }
+
+ function getPadding()
+ {
+ return {x = anx(m_paddingPx.x), y = any(m_paddingPx.y)}
+ }
+
+ function setPadding(x, y)
+ {
+ setPaddingPx(nax(x), nay(y))
+ }
+
+ function setText(text)
+ {
+ base.setText(text)
+ setPaddingPx(m_paddingPx.x, m_paddingPx.y)
+ }
+
+ static function onMouseIn(self)
+ {
+ if (!self.toolTip)
+ return
+
+ activeToolTip = self.toolTip
+
+ local toolTip = activeToolTip.getToolTip(self)
+
+ if (toolTip)
+ activeToolTip.setText(toolTip)
+
+ toolTipInterval = 0
+ }
+
+ static function onMouseOut(self)
+ {
+ if (!self.toolTip)
+ return
+
+ activeToolTip = null
+ }
+
+ static function onRender()
+ {
+ if (!activeToolTip)
+ return
+
+ if (toolTipInterval >= TOOLTIP_INTERVAL)
+ return
+
+ toolTipInterval += getFrameTime()
+
+ if (toolTipInterval >= TOOLTIP_INTERVAL)
+ {
+ local cursorPosition = getCursorPositionPx()
+
+ activeToolTip.setPositionPx(cursorPosition.x, cursorPosition.y + 15)
+ activeToolTip.top()
+ activeToolTip.setVisible(true)
+ }
+ }
+
+ static function onMouseMove(newCursorX, newCursorY, oldCursorX, oldCursorY)
+ {
+ if (!activeToolTip)
+ return
+
+ activeToolTip.setVisible(false)
+ toolTipInterval = 0
+ }
+}
+
+addEventHandler("GUI.onMouseIn", GUI.ToolTip.onMouseIn)
+addEventHandler("GUI.onMouseOut", GUI.ToolTip.onMouseOut)
+addEventHandler("onRender", GUI.ToolTip.onRender)
+addEventHandler("onMouseMove", GUI.ToolTip.onMouseMove)
diff --git a/lib/gui-framework/elements/window.nut b/lib/gui-framework/elements/window.nut
new file mode 100644
index 0000000..2a12fcd
--- /dev/null
+++ b/lib/gui-framework/elements/window.nut
@@ -0,0 +1,160 @@
+local activeWindow = null
+
+class GUI.Window extends classes(GUI.Texture, GUI.Collection)
+{
+ static windowsList = []
+ static m_cursorOffset = {x = 0, y = 0}
+
+#public:
+ constructor(x, y, w, h, texture, textureAlign = null, enabled = false, animate = false)
+ {
+ GUI.Texture.constructor.call(this, x, y, w, h, texture)
+ GUI.Collection.constructor.call(this, x, y)
+
+ if (!enabled)
+ setDisabled(true)
+
+ if(animate)
+ animation = GUI.Animation(this)
+
+ /*
+ if(textureAlign)
+ //func center
+ */
+
+ windowsList.append(this)
+ }
+
+ function destroy()
+ {
+ foreach (index, window in windowsList)
+ {
+ if (window == this)
+ {
+ windowsList.remove(index)
+ break
+ }
+ }
+
+ GUI.Texture.destroy.call(this)
+ }
+
+ function isMouseAt()
+ {
+ foreach(item, offset in childs)
+ {
+ if (item.isMouseAt())
+ return false
+ }
+
+ return base.isMouseAt()
+ }
+
+ function top()
+ {
+ GUI.Texture.top.call(this)
+ GUI.Collection.top.call(this)
+ }
+
+ function setVisible(visible, affectChilds = true)
+ {
+ GUI.Texture.setVisible.call(this, visible)
+
+ if (affectChilds)
+ GUI.Collection.setVisible.call(this, visible)
+ }
+
+ function setPosition(x, y)
+ {
+ setPositionPx(nax(x), nay(y))
+ }
+
+ function setPositionPx(x, y)
+ {
+ GUI.Texture.setPositionPx.call(this, x, y)
+ GUI.Collection.setPositionPx.call(this, x, y)
+ }
+
+ function setColor(r, g, b, affectChilds = false)
+ {
+ base.setColor(r, g, b)
+
+ if (affectChilds)
+ {
+ foreach(item, offset in childs)
+ item.setColor(r, g, b)
+ }
+ }
+
+ function setAlpha(alpha, affectChilds = false)
+ {
+ base.setAlpha(alpha)
+
+ if (affectChilds)
+ {
+ foreach(item, offset in childs)
+ item.setAlpha(alpha)
+ }
+ }
+
+ static function hideAll()
+ {
+ foreach(window in GUI.Window.windowsList)
+ {
+ if(window.isVisible())
+ window.setVisible(false)
+ }
+ }
+
+ static function isOpen()
+ {
+ foreach(window in GUI.Window.windowList)
+ {
+ if(window.isVisible())
+ return true
+ }
+
+ return false
+ }
+
+ static function onMouseMove(cursorX, cursorY, oldCursorX, oldCursorY)
+ {
+ if (!activeWindow)
+ return
+
+ local cursorPosition = getCursorPositionPx()
+ activeWindow.setPositionPx(cursorPosition.x + activeWindow.m_cursorOffset.x, cursorPosition.y + activeWindow.m_cursorOffset.y)
+ }
+
+ static function onMouseDown(self, button)
+ {
+ if (button != MOUSE_LMB)
+ return
+
+ if (!(self instanceof GUI.Window))
+ return
+
+ local cursorPosition = getCursorPositionPx()
+ local position = self.getPositionPx()
+
+ self.m_cursorOffset.x = position.x - cursorPosition.x
+ self.m_cursorOffset.y = position.y - cursorPosition.y
+
+ activeWindow = self
+ }
+
+ static function onMouseUp(self, button)
+ {
+ if (button != MOUSE_LMB)
+ return
+
+ if (!activeWindow)
+ return
+
+ activeWindow = null
+ }
+}
+
+addEventHandler("onMouseMove", GUI.Window.onMouseMove)
+addEventHandler("GUI.onMouseDown", GUI.Window.onMouseDown)
+addEventHandler("GUI.onMouseUp", GUI.Window.onMouseUp)
diff --git a/lib/gui-framework/examples/bar.nut b/lib/gui-framework/examples/bar.nut
new file mode 100644
index 0000000..a0555bb
--- /dev/null
+++ b/lib/gui-framework/examples/bar.nut
@@ -0,0 +1,31 @@
+local horizontalBar = GUI.Bar(100, 7525, anx(180), any(20), anx(7), any(3), "BAR_BACK.TGA", "BAR_MISC.TGA", Orientation.Horizontal)
+local verticalBar = GUI.Bar(100, 5000, anx(20), any(180), anx(3), any(10), "MENU_INGAME.TGA", "INV_SLOT_EQUIPPED.TGA", Orientation.Vertical, Align.Right)
+
+addEventHandler("onInit",function()
+{
+ horizontalBar.setVisible(true)
+ horizontalBar.setStretching(false)
+
+ verticalBar.setVisible(true)
+ verticalBar.setStretching(false)
+})
+
+addEventHandler("onMouseClick",function(btn)
+{
+ if (btn != MOUSE_RMB)
+ return
+
+ local value = horizontalBar.getValue()
+
+ if (value >= horizontalBar.getMaximum())
+ value = horizontalBar.getMinimum()
+
+ horizontalBar.setValue(value + 10)
+
+ value = verticalBar.getValue()
+
+ if (value >= verticalBar.getMaximum())
+ value = verticalBar.getMinimum()
+
+ verticalBar.setValue(value + 10)
+})
diff --git a/lib/gui-framework/examples/button.nut b/lib/gui-framework/examples/button.nut
new file mode 100644
index 0000000..dd42b62
--- /dev/null
+++ b/lib/gui-framework/examples/button.nut
@@ -0,0 +1,46 @@
+local window = GUI.Window(0, 0, anx(400), any(200), "MENU_INGAME.TGA", null, true)
+local closeButton = GUI.Button(anx(350), 0, anx(50), any(25), "INV_SLOT_FOCUS.TGA", "X", window)
+local msg = GUI.Draw(anx(70), any(80), "Would you like an update?", window)
+local yesButton = GUI.Button(anx(125), any(120), anx(50), any(25), "INV_SLOT_FOCUS.TGA", "Yes", window)
+local noButton = GUI.Button(anx(225), any(120), anx(50), any(25), "INV_SLOT_FOCUS.TGA", "No", window)
+
+addEventHandler("onInit",function()
+{
+ setCursorVisible(true)
+
+ window.setVisible(true)
+})
+
+addEventHandler("GUI.onClick", function(self)
+{
+ switch (self)
+ {
+ case closeButton:
+ window.setVisible(false)
+ break
+
+ case yesButton:
+ msg.setText("Update completed [#7676f7]successfully!")
+ break
+
+ case noButton:
+ msg.setText("Nah.. [#F60005]that's a pitty")
+ break
+ }
+})
+
+addEventHandler("GUI.onMouseIn", function(self)
+{
+ if (!(self instanceof GUI.Button))
+ return
+
+ self.setColor(255, 0, 0)
+})
+
+addEventHandler("GUI.onMouseOut", function(self)
+{
+ if (!(self instanceof GUI.Button))
+ return
+
+ self.setColor(255, 255, 255)
+})
diff --git a/lib/gui-framework/examples/checkbox.nut b/lib/gui-framework/examples/checkbox.nut
new file mode 100644
index 0000000..d0f6cdc
--- /dev/null
+++ b/lib/gui-framework/examples/checkbox.nut
@@ -0,0 +1,10 @@
+local window = GUI.Window(0, 0, anx(400), any(200), "MENU_INGAME.TGA", null, true)
+
+local drawCheckBox = GUI.CheckBox(anx(125), any(75), anx(50), any(40), "INV_SLOT_EQUIPPED_FOCUS.TGA", "X", window)
+local textureCheckBox = GUI.CheckBox(anx(185), any(75), anx(50), any(40), "INV_SLOT_EQUIPPED_FOCUS.TGA", "INV_SLOT_EQUIPPED_HIGHLIGHTED_FOCUS.TGA", window)
+
+addEventHandler("onInit",function()
+{
+ window.setVisible(true)
+ setCursorVisible(true)
+})
diff --git a/lib/gui-framework/examples/draw.nut b/lib/gui-framework/examples/draw.nut
new file mode 100644
index 0000000..9b90bc7
--- /dev/null
+++ b/lib/gui-framework/examples/draw.nut
@@ -0,0 +1,46 @@
+local draw = GUI.Draw(1000, 1000, "[#F60005]E[#aadd20]x[#aaffff]a[#ed00ef]m[#ff7800]p[#2900ff]l[#F60005]e [#50cc29]T[#cc298a]e[#F60005]x[#50cc29]t")
+local draw2 = GUI.Draw(1000, 1250, "HOVER me")
+
+draw2.resize(10) // reserving 10 letters for draw2
+
+addEventHandler("onInit",function()
+{
+ draw.setVisible(true)
+ draw2.setVisible(true)
+ /*
+ draw.letters[0].setColor(255, 0, 0)
+ draw.letters[1].setColor(0, 255, 0)
+ draw.letters[2].setColor(0, 0, 255)
+ */
+ //draw.setFont("FONT_OLD_20_WHITE_HI.TGA")
+ //draw.setLetterSpacingPx(10)
+ setCursorVisible(true)
+})
+
+addEventHandler("GUI.onMouseIn", function(self)
+{
+ switch (self)
+ {
+ case draw:
+ self.setColor(255, 0, 0)
+ break
+
+ case draw2:
+ self.setText("HOVER me")
+ break
+ }
+})
+
+addEventHandler("GUI.onMouseOut", function(self)
+{
+ switch (self)
+ {
+ case draw:
+ self.setText("[#F60005]E[#aadd20]x[#aaffff]a[#ed00ef]m[#ff7800]p[#2900ff]l[#F60005]e [#50cc29]T[#cc298a]e[#F60005]x[#50cc29]t")
+ break
+
+ case draw2:
+ self.setText("HOVER")
+ break
+ }
+})
diff --git a/lib/gui-framework/examples/gridlist.nut b/lib/gui-framework/examples/gridlist.nut
new file mode 100644
index 0000000..bab402f
--- /dev/null
+++ b/lib/gui-framework/examples/gridlist.nut
@@ -0,0 +1,204 @@
+local randomChar = @() rand() % 255
+
+local window = GUI.Window(500, 1500, anx(700), any(400), "MENU_INGAME.TGA", null, true)
+local grid = GUI.GridList(anx(400), 0, anx(300), any(300), "MENU_INGAME.TGA", "MENU_INGAME.TGA", "BAR_MISC.TGA", "O.TGA", "U.TGA", window)
+grid.setMarginPx(10, 0, 0, 10)
+grid.setSpacingPx(5)
+grid.setRowSizePx(grid.getRowSizePx() + 10)
+
+local playerColumn = grid.addColumn("Player", anx(132), Align.Center)
+playerColumn.draw.setColor(145, 175, 205)
+playerColumn.setFile("INV_SLOT_EQUIPPED_HIGHLIGHTED.TGA")
+playerColumn.setSizePx(playerColumn.getSizePx().width, grid.getRowSizePx())
+
+local pingColumn = grid.addColumn("Ping", anx(133), Align.Center)
+pingColumn.draw.setColor(190, 210, 240)
+pingColumn.setFile("INV_SLOT_EQUIPPED_HIGHLIGHTED.TGA")
+pingColumn.setSizePx(playerColumn.getSizePx().width, grid.getRowSizePx())
+
+{
+ local ASCIILetter = 'A'
+
+ for(local i = 1; i <= 26; i++)
+ {
+ local index = grid.addRow(ASCIILetter.tochar().tostring(), randomChar())
+
+ foreach (row in grid.rows)
+ {
+ foreach (cell in row.cells)
+ {
+ cell.draw.setColor(randomChar(), randomChar(), randomChar())
+ cell.setFile("INV_SLOT_EQUIPPED.TGA")
+ }
+ }
+
+ ++ASCIILetter
+ }
+}
+
+local addFirstRowButton = GUI.Button(anx(60), any(0), anx(300), any(40), "MENU_INGAME.TGA", "Add first row", window)
+local addLastRowButton = GUI.Button(anx(60), any(40), anx(300), any(40), "MENU_INGAME.TGA", "Add last row", window)
+local removeFirstRowButton = GUI.Button(anx(60), any(80), anx(300), any(40), "MENU_INGAME.TGA", "Remove first row", window)
+local removeLastRowButton = GUI.Button(anx(60), any(120), anx(300), any(40), "MENU_INGAME.TGA", "Remove last row", window)
+local addPlayerColumnFirstCellButton = GUI.Button(anx(60), any(160), anx(300), any(40), "MENU_INGAME.TGA", "Add Player Column first cell", window)
+local addPingColumnFirstCellButton = GUI.Button(anx(60), any(200), anx(300), any(40), "MENU_INGAME.TGA", "Add Ping Column first cell", window)
+local removePlayerColumnFirstCellButton = GUI.Button(anx(60), any(240), anx(300), any(40), "MENU_INGAME.TGA", "Remove Player Column first cell", window)
+local removePingColumnFirstCellButton = GUI.Button(anx(60), any(280), anx(300), any(40), "MENU_INGAME.TGA", "Remove Ping Column first cell", window)
+local removePlayerColumnButton = GUI.Button(anx(60), any(320), anx(300), any(40), "MENU_INGAME.TGA", "Remove Player Column", window)
+local removePingColumnButton = GUI.Button(anx(60), any(360), anx(300), any(40), "MENU_INGAME.TGA", "Remove Ping Column", window)
+
+addEventHandler("onInit", function()
+{
+ window.setVisible(true)
+ setCursorVisible(true)
+})
+
+addEventHandler("GUI.onClick", function(self)
+{
+ if (!(self instanceof GUI.Button))
+ return
+
+ switch (self)
+ {
+ case addFirstRowButton:
+ if (!grid.columns.len())
+ return
+
+ grid.insertRow(0, "1.Cell First", "2.Cell First")
+ break
+
+ case addLastRowButton:
+ if (!grid.columns.len())
+ return
+
+ grid.addRow("1.Cell Last", "2.Cell Last")
+ break
+
+ case removeFirstRowButton:
+ if (!(0 in grid.columns))
+ return
+
+ if (!grid.rows.len())
+ return
+
+ grid.removeRow(0)
+ break
+
+ case removeLastRowButton:
+ if (!(0 in grid.columns))
+ return
+
+ local rowsCount = grid.rows.len()
+
+ if (!rowsCount)
+ return
+
+ grid.removeRow(rowsCount - 1)
+ break
+
+ case addPlayerColumnFirstCellButton:
+ if (!playerColumn)
+ return
+
+ if (!(0 in grid.rows))
+ return
+
+ if (grid.rows[0].cells[playerColumn.id])
+ return
+
+ grid.rows[0].insertCell(playerColumn.id, "Player")
+
+ grid.rows[0].cells[playerColumn.id].draw.setColor(randomChar(), randomChar(), randomChar())
+ grid.rows[0].cells[playerColumn.id].setFile("INV_SLOT_EQUIPPED.TGA")
+
+ break
+
+ case addPingColumnFirstCellButton:
+ if (!pingColumn)
+ return
+
+ if (!(0 in grid.rows))
+ return
+
+ if (grid.rows[0].cells[pingColumn.id])
+ return
+
+ grid.rows[0].insertCell(pingColumn.id, randomChar())
+
+ grid.rows[0].cells[pingColumn.id].draw.setColor(randomChar(), randomChar(), randomChar())
+ grid.rows[0].cells[pingColumn.id].setFile("INV_SLOT_EQUIPPED.TGA")
+
+ break
+
+ case removePlayerColumnFirstCellButton:
+ if (!playerColumn)
+ return
+
+ grid.rows[0].removeCell(playerColumn.id)
+
+ break
+
+ case removePingColumnFirstCellButton:
+ if (!pingColumn)
+ return
+
+ grid.rows[0].removeCell(pingColumn.id)
+
+ break
+
+ case removePlayerColumnButton:
+ if (!playerColumn)
+ return
+
+ playerColumn = grid.removeColumn(playerColumn.id)
+ break
+
+ case removePingColumnButton:
+ if (!pingColumn)
+ return
+
+ pingColumn = grid.removeColumn(pingColumn.id)
+ break
+ }
+})
+
+addEventHandler("GUI.onClick", function(self)
+{
+ if (!(self instanceof GUI.GridListCell))
+ return
+
+ local row = self.parent
+ local gridlist = row.parent
+
+ if (gridlist != grid)
+ return
+
+ foreach (cell in row.cells)
+ cell.draw.setColor(randomChar(), randomChar(), randomChar())
+})
+
+local columnsSortDirection = array(grid.columns.len(), 1)
+
+addEventHandler("GUI.onClick", function(self)
+{
+ if (!(self instanceof GUI.GridListColumn))
+ return
+
+ if (self.parent != grid)
+ return
+
+ columnsSortDirection[self.id] = -columnsSortDirection[self.id]
+
+ grid.sort(function(a, b)
+ {
+ local aValue = a.cells[self.id].getValue()
+ local bValue = b.cells[self.id].getValue()
+
+ if (aValue > bValue)
+ return -columnsSortDirection[self.id]
+ else if (aValue < bValue)
+ return columnsSortDirection[self.id]
+
+ return 0
+ })
+})
diff --git a/lib/gui-framework/examples/input.nut b/lib/gui-framework/examples/input.nut
new file mode 100644
index 0000000..9664c5f
--- /dev/null
+++ b/lib/gui-framework/examples/input.nut
@@ -0,0 +1,68 @@
+local window = GUI.Window(anx(100), any(100), anx(400), any(400), "MENU_INGAME.TGA", null, true)
+local textInput = GUI.Input(anx(100), any(10), anx(300), any(50), "DLG_CONVERSATION.TGA", "FONT_OLD_20_WHITE_HI.TGA", Input.Text, Align.Left, "Text", 6, window)
+textInput.selector = "|"
+local passwordInput = GUI.Input(anx(100), any(400), anx(300), any(50), "DLG_CONVERSATION.TGA", "FONT_OLD_20_WHITE_HI.TGA", Input.Password, Align.Center, "Password", 2)
+local numbersInput = GUI.Input(anx(100), any(500), anx(300), any(50), "DLG_CONVERSATION.TGA", "FONT_OLD_20_WHITE_HI.TGA", Input.Numbers, Align.Right, "Number", 2)
+numbersInput.setText("GRACZ_")
+
+addEventHandler("onInit",function()
+{
+ setCursorVisible(true)
+
+ window.setVisible(true)
+ passwordInput.setDisabled(false);
+ passwordInput.setVisible(true)
+ numbersInput.setDisabled(false);
+ numbersInput.setVisible(true)
+})
+
+addEventHandler("GUI.onInputInsertLetter", function(element, text)
+{
+ if(element == textInput)
+ print(text)
+})
+
+addEventHandler("GUI.onInputRemoveLetter", function(element, letter)
+{
+ if(element == textInput)
+ print(letter)
+})
+
+addEventHandler("GUI.onInputActive", function(element)
+{
+ if(element == textInput)
+ print("Aktywowano")
+})
+
+addEventHandler("GUI.onInputDeactive", function(element)
+{
+ if(element == textInput)
+ print("Dezaktywowano")
+})
+
+/*
+GUI.Input(x, y, w, h, file, font, type, align = Align.Left, placeholder = "", margin = 2, node = null)
+GUI.Input.setVisible(bool)
+GUI.Input.setPosition(x, y)
+GUI.Input.setPositionPx(x, y)
+GUI.Input.setDisabled(disable)//applies to events
+GUI.Input.setActivity(status)
+GUI.Input.setColor(r, g, b)
+GUI.Input.setAlpha(alpha)
+GUI.Input.isFocused()//return bool
+GUI.Input.getAlpha()//return int
+GUI.Input.getColor() //{r, g, b}
+GUI.Input.getPosition()//{x, y}
+GUI.Input.getPositionPx()//{x, y}
+GUI.Input.getVisible()//return bool
+GUI.Input.selector = "|"
+GUI.Input.maxLetters = 999
+GUI.Input.setText(string text)
+GUI.Input.getText()
+
+//events
+GUI.onInputInsertLetter(input, letter)
+GUI.onInputRemoveLetter(input, letter)
+GUI.onInputActive(input)
+GUI.onInputDeactive(input)
+*/
\ No newline at end of file
diff --git a/lib/gui-framework/examples/multidraw.nut b/lib/gui-framework/examples/multidraw.nut
new file mode 100644
index 0000000..eb19bf9
--- /dev/null
+++ b/lib/gui-framework/examples/multidraw.nut
@@ -0,0 +1,20 @@
+local multidraw = GUI.MultiDraw(0, 0)
+multidraw.addLine("This line is red")
+multidraw.addLine("This line is green")
+multidraw.addLine("This line is blue")
+
+multidraw.addLine("This line is white", 0)
+
+multidraw.setFont("FONT_OLD_20_WHITE_HI.TGA")
+
+multidraw.setColor(255, 0, 0, 1, 1)
+multidraw.setColor(0, 255, 0, 2, 2)
+multidraw.setColor(0, 0, 255, 3, 3)
+
+multidraw.setAlpha(200)
+multidraw.setAlpha(155, 1, 3)
+
+addEventHandler("onInit", function()
+{
+ multidraw.setVisible(true)
+})
diff --git a/lib/gui-framework/examples/radiobutton.nut b/lib/gui-framework/examples/radiobutton.nut
new file mode 100644
index 0000000..eb95e6d
--- /dev/null
+++ b/lib/gui-framework/examples/radiobutton.nut
@@ -0,0 +1,26 @@
+local description = GUI.Draw(anx(0), any(125), "Choose your gender:")
+
+local maleRadio = GUI.RadioButton(anx(0), any(147), anx(20), any(15), "INV_SLOT_EQUIPPED_FOCUS.TGA", "O", "Gender")
+local maleDescriptipn = GUI.Draw(anx(25), any(147), "Male")
+
+local femaleRadio = GUI.RadioButton(anx(0), any(169), anx(20), any(15), "INV_SLOT_EQUIPPED_FOCUS.TGA", "O", "Gender")
+local femaleDescriptipn = GUI.Draw(anx(25), any(169), "Female")
+
+local soirefRadio = GUI.RadioButton(anx(0), any(191), anx(20), any(15), "INV_SLOT_EQUIPPED_FOCUS.TGA", "O", "Gender")
+local soirefDescriptipn = GUI.Draw(anx(25), any(191), "Soiref")
+
+addEventHandler("onInit",function()
+{
+ description.setVisible(true)
+
+ maleRadio.setVisible(true)
+ maleDescriptipn.setVisible(true)
+
+ femaleRadio.setVisible(true)
+ femaleDescriptipn.setVisible(true)
+
+ soirefRadio.setVisible(true)
+ soirefDescriptipn.setVisible(true)
+
+ setCursorVisible(true)
+})
diff --git a/lib/gui-framework/examples/range.nut b/lib/gui-framework/examples/range.nut
new file mode 100644
index 0000000..2fd2dd9
--- /dev/null
+++ b/lib/gui-framework/examples/range.nut
@@ -0,0 +1,27 @@
+local window = GUI.Window(0, 0, anx(400), any(200), "MENU_INGAME.TGA", null, true)
+
+local infoDraw = GUI.Draw(anx(50), any(20), "0", window)
+
+local horizontalRange = GUI.Range(anx(50), 0, anx(200), any(20), "MENU_SLIDER_BACK.TGA" "MENU_SLIDER_POS.TGA", Orientation.Horizontal, window)
+horizontalRange.setMaximum(100)
+horizontalRange.setMinimum(0)
+horizontalRange.setStep(1)
+
+horizontalRange.indicator.setSizePx(RANGE_INDICATOR_SIZE / 2, horizontalRange.indicator.getSizePx().height)
+horizontalRange.setMarginPx(5, 0, 10, 0)
+
+local verticalRange = GUI.Range(anx(30), 0, anx(20), any(200), "MENU_INGAME.TGA", "MENU_SLIDER_POS.TGA", Orientation.Vertical, window)
+verticalRange.setMaximum(50.0)
+verticalRange.setMinimum(0.0)
+verticalRange.setStep(0.5)
+
+addEventHandler("onInit",function()
+{
+ setCursorVisible(true)
+ window.setVisible(true)
+})
+
+addEventHandler("GUI.onChange", function(self)
+{
+ infoDraw.setText(self.getValue())
+})
diff --git a/lib/gui-framework/examples/scrollbar.nut b/lib/gui-framework/examples/scrollbar.nut
new file mode 100644
index 0000000..a392517
--- /dev/null
+++ b/lib/gui-framework/examples/scrollbar.nut
@@ -0,0 +1,9 @@
+local window = GUI.Window(anx(50), any(50), anx(400), any(200), "MENU_INGAME.TGA", null, true)
+local verticalScroll = GUI.ScrollBar(anx(400), 0, anx(20), any(200), "MENU_INGAME.TGA", "BAR_MISC.TGA", "O.TGA", "U.TGA", Orientation.Vertical, window)
+local horizontalScroll = GUI.ScrollBar(0, any(200), anx(400), any(20), "MENU_INGAME.TGA", "BAR_MISC.TGA", "L.TGA", "R.TGA", Orientation.Horizontal, window)
+
+addEventHandler("onInit",function()
+{
+ setCursorVisible(true)
+ window.setVisible(true)
+})
diff --git a/lib/gui-framework/examples/slider.nut b/lib/gui-framework/examples/slider.nut
new file mode 100644
index 0000000..fd5c362
--- /dev/null
+++ b/lib/gui-framework/examples/slider.nut
@@ -0,0 +1,13 @@
+local window = GUI.Window(0, 0, anx(400), any(300), "MENU_INGAME.TGA", null, true)
+
+local horizontalSlider = GUI.Slider(anx(30), any(5), anx(200), any(30) anx(7), any(3), "BAR_BACK.TGA", "BAR_MISC.TGA", "MENU_SLIDER_POS.TGA", Orientation.Horizontal, Align.Left, window)
+local verticalSlider = GUI.Slider(anx(5), any(30), anx(30), any(200) anx(3), any(7), "MENU_INGAME.TGA", "INV_SLOT_EQUIPPED.TGA", "MENU_SLIDER_POS.TGA", Orientation.Vertical, Align.Left, window)
+
+addEventHandler("onInit",function()
+{
+ setCursorVisible(true)
+ window.setVisible(true)
+
+ horizontalSlider.bar.setStretching(false)
+ verticalSlider.bar.setStretching(false)
+})
diff --git a/lib/gui-framework/examples/tabpanel.nut b/lib/gui-framework/examples/tabpanel.nut
new file mode 100644
index 0000000..e437948
--- /dev/null
+++ b/lib/gui-framework/examples/tabpanel.nut
@@ -0,0 +1,82 @@
+local horizontalPanel = GUI.TabPanel(0, 0, anx(400), any(TAB_HEIGHT), "MENU_INGAME.TGA")
+local horizontalTabs = []
+
+horizontalTabs.push(horizontalPanel.addTab("INV_SLOT_EQUIPPED.TGA", "Page 1"))
+horizontalTabs.push(horizontalPanel.addTab("INV_SLOT_EQUIPPED.TGA", "Page 2"))
+horizontalTabs.push(horizontalPanel.addTab("INV_SLOT_EQUIPPED.TGA", "Page 3"))
+horizontalTabs.push(horizontalPanel.addTab("INV_SLOT_EQUIPPED.TGA", "Page 4"))
+
+horizontalPanel.setMarginPx(5, 10, 5, 10)
+
+local verticalPanel = GUI.TabPanel(anx(400), any(TAB_HEIGHT), anx(TAB_WIDTH), any(TAB_HEIGHT * 4), "", Orientation.Vertical)
+local verticalTabs = []
+
+verticalTabs.push(verticalPanel.addTab("INV_SLOT_EQUIPPED.TGA", "Page 1"))
+verticalTabs.push(verticalPanel.addTab("INV_SLOT_EQUIPPED.TGA", "Page 2"))
+verticalTabs.push(verticalPanel.addTab("INV_SLOT_EQUIPPED.TGA", "Page 3"))
+verticalTabs.push(verticalPanel.addTab("INV_SLOT_EQUIPPED.TGA", "Page 4"))
+
+local debugCollection = GUI.Collection(anx(0), any(500))
+local addLastTabButton = GUI.Button(anx(0), any(0), anx(200), any(40), "MENU_INGAME.TGA", "Add last tab", debugCollection)
+local removeLastTabButton = GUI.Button(anx(200), any(0), anx(200), any(40), "MENU_INGAME.TGA", "Remove last tab", debugCollection)
+local addFirstTabButton = GUI.Button(anx(0), any(40), anx(200), any(40), "MENU_INGAME.TGA", "Add first tab", debugCollection)
+local removeFirstTabButton = GUI.Button(anx(200), any(40), anx(200), any(40), "MENU_INGAME.TGA", "Remove first tab", debugCollection)
+
+addEventHandler("onInit", function()
+{
+ setCursorVisible(true)
+
+ horizontalPanel.setVisible(true)
+ verticalPanel.setVisible(true)
+
+ debugCollection.setVisible(true)
+})
+
+addEventHandler("GUI.onSwitch",function(current, previous)
+{
+ if (previous)
+ previous.setFile("INV_SLOT_EQUIPPED.TGA")
+
+ if (current)
+ current.setFile("INV_SLOT_EQUIPPED_FOCUS.TGA")
+})
+
+addEventHandler("GUI.onClick", function(self)
+{
+ switch (self)
+ {
+ case addLastTabButton:
+ horizontalTabs.push(horizontalPanel.addTab("INV_SLOT_EQUIPPED.TGA", "Page "+(horizontalPanel.tabs.len() + 1)))
+ verticalTabs.push(verticalPanel.addTab("INV_SLOT_EQUIPPED.TGA", "Page "+(verticalPanel.tabs.len() + 1)))
+ break
+
+ case removeLastTabButton:
+ local len = horizontalPanel.tabs.len()
+
+ if (!len)
+ return
+
+ horizontalPanel.removeTab(len - 1)
+ horizontalTabs.remove(len - 1)
+
+ verticalPanel.removeTab(len - 1)
+ verticalTabs.remove(len - 1)
+ break
+
+ case addFirstTabButton:
+ horizontalTabs.insert(0, horizontalPanel.insertTab(0, "INV_SLOT_EQUIPPED.TGA", "Page "+(horizontalPanel.tabs.len() + 1)))
+ verticalTabs.insert(0, verticalPanel.insertTab(0, "INV_SLOT_EQUIPPED.TGA", "Page "+(verticalPanel.tabs.len() + 1)))
+ break
+
+ case removeFirstTabButton:
+ if (!(0 in horizontalTabs))
+ return
+
+ horizontalTabs.remove(0)
+ horizontalPanel.removeTab(0)
+
+ verticalTabs.remove(0)
+ verticalPanel.removeTab(0)
+ break
+ }
+})
diff --git a/lib/gui-framework/examples/texture.nut b/lib/gui-framework/examples/texture.nut
new file mode 100644
index 0000000..782a1b1
--- /dev/null
+++ b/lib/gui-framework/examples/texture.nut
@@ -0,0 +1,53 @@
+local texture = GUI.Texture(0, 0, 2048, 2048, "INV_TITEL.TGA")
+texture.setScaling(true)
+
+local animTexture = GUI.Texture(2048, 4096, 4096, 4096, "OWODWFALL_HITSURFACE_A0.TGA")
+
+animTexture.setFPS(10)
+animTexture.setBeginFrame(0)
+animTexture.setEndFrame(14)
+
+addEventHandler("onInit", function()
+{
+ texture.setVisible(true)
+ animTexture.setVisible(true)
+
+ setCursorVisible(true)
+})
+
+addEventHandler("GUI.onMouseIn", function(self)
+{
+ if (self != texture)
+ return
+
+ texture.setColor(255, 255, 0)
+ animTexture.stop()
+})
+
+addEventHandler("GUI.onMouseOut", function(self)
+{
+ if (self != texture)
+ return
+
+ texture.setColor(255, 255, 255)
+ animTexture.play()
+})
+
+addEventHandler("GUI.onMouseDown", function(self, btn)
+{
+ if (self != texture)
+ return
+
+ texture.setColor(0, 255, 0)
+})
+
+addEventHandler("GUI.onMouseUp", function(self, btn)
+{
+ if (self != texture)
+ return
+
+ if (self.isMouseAt())
+ texture.setColor(255, 255, 0)
+ else
+ texture.setColor(255, 255, 255)
+})
diff --git a/lib/gui-framework/examples/tooltip.nut b/lib/gui-framework/examples/tooltip.nut
new file mode 100644
index 0000000..606deec
--- /dev/null
+++ b/lib/gui-framework/examples/tooltip.nut
@@ -0,0 +1,62 @@
+/*
+ TODO:
+ 1.setMarginPx powinno ustawiać margines na brzegach, oraz setText/setSize/setSizePx też to powinno wspierać?
+
+*/
+
+local redButton = GUI.Button(0, 0, anx(120), any(50), "RED.TGA")
+local greenButton = GUI.Button(anx(20), any(20), anx(120), any(50), "GREEN.TGA")
+local blueButton = GUI.Button(anx(40), any(40), anx(120), any(50), "BLUE.TGA")
+local whiteButton = GUI.Button(anx(60), any(60), anx(120), any(50), "WHITE.TGA")
+local blackButton = GUI.Button(anx(80), any(80), anx(120), any(50), "BROWN.TGA")
+
+local button = GUI.Button(2048, 2048, 4096, 4096, "BROWN.TGA")
+local button2 = GUI.Button(4096, 4096, 8192, 8192, "GREEN.TGA")
+
+local infoDraw = GUI.Draw(anx(160), 0, "Hover me, for more info...")
+infoDraw.setFont("FONT_OLD_20_WHITE_HI.TGA")
+infoDraw.toolTip = GUI.ToolTip(anx(10), any(5), "BROWN.TGA", "This buttons shows, how Framework\nworks with depth feature.\nYou can hover the buttons or click them,\nto test the behaviour.")
+
+local toolTip = GUI.ToolTip(anx(4), any(2), "MENU_INGAME.TGA", "")
+toolTip.setToolTip(redButton, "[#FF0000]Red")
+toolTip.setToolTip(greenButton, "[#00FF00]Green")
+toolTip.setToolTip(blueButton, "[#00CCFF]Blue")
+toolTip.setToolTip(whiteButton, "[#FFFFFF]White")
+toolTip.setToolTip(blackButton, "[#B26630]Brown")
+
+addEventHandler("onInit",function()
+{
+ redButton.setVisible(true)
+ greenButton.setVisible(true)
+ blueButton.setVisible(true)
+ whiteButton.setVisible(true)
+ blackButton.setVisible(true)
+
+ infoDraw.setVisible(true)
+
+ setCursorVisible(true)
+})
+
+addEventHandler("GUI.onMouseIn",function(self)
+{
+ if (!(self instanceof GUI.Button))
+ return
+
+ self.setAlpha(125)
+})
+
+addEventHandler("GUI.onMouseOut",function(self)
+{
+ if (!(self instanceof GUI.Button))
+ return
+
+ self.setAlpha(255)
+})
+
+addEventHandler("GUI.onClick", function(self)
+{
+ if (!(self instanceof GUI.Button))
+ return
+
+ self.top()
+})
diff --git a/lib/gui-framework/examples/window.nut b/lib/gui-framework/examples/window.nut
new file mode 100644
index 0000000..9f6d012
--- /dev/null
+++ b/lib/gui-framework/examples/window.nut
@@ -0,0 +1,55 @@
+local window = GUI.Window(anx(100), any(100), anx(400), any(400), "MENU_INGAME.TGA", null, true)
+window.setAlpha(200)
+window.setColor(255, 0, 0, true)
+window.setSizePx(500, 300)
+window.setSizePx(500, 300)
+
+addEventHandler("onInit", function()
+{
+ enableEvent_Render(true)
+ window.setVisible(true)
+ setCursorVisible(true)
+})
+
+addEventHandler("GUI.onOpen", function(element)
+{
+ if(element == window)
+ print("Window was opened")
+});
+
+addEventHandler("GUI.onClose", function(element)
+{
+ if(element == window)
+ print("Window was closed")
+});
+
+
+addEventHandler("onKey", function(key)
+{
+ if(key == KEY_P)
+ window.setVisible(!window.getVisible())
+});
+
+/*
+GUI.Window(x, y, w, h, texture, textureAlign = null, moveEnable = false, animate = false)
+GUI.Window.setVisible(bool)
+GUI.Window.setPosition(x, y, syncVector = true)
+GUI.Window.setPositionPx(x, y, syncVector = true)
+GUI.Window.setSizePx(w, h)
+GUI.Window.setSize(w, h)
+GUI.Window.setTexture(_file)
+GUI.Window.setAlpha(_alpha)
+GUI.Window.setColor(_r, _g, _b, colorAll = false)
+GUI.Window.isVisible()//return bool
+GUI.Window.getPositionPx()//return {x, y}
+GUI.Window.getPosition()//return {x, y}
+GUI.Window.getSizePx()//return {width, height}
+GUI.Window.getSize()//return {width, height}
+GUI.Window.getTexture()//return string
+GUI.Window.getAlpha()//return int
+GUI.Window.getColor()//return {r, g, b}
+
+//Global
+GUI.Window.hideAll();
+GUI.Window.isOpen()//return bool
+*/
diff --git a/lib/gui-framework/gui.xml b/lib/gui-framework/gui.xml
new file mode 100644
index 0000000..acbb7e0
--- /dev/null
+++ b/lib/gui-framework/gui.xml
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/lib/gui-framework/main.nut b/lib/gui-framework/main.nut
new file mode 100644
index 0000000..4466ab3
--- /dev/null
+++ b/lib/gui-framework/main.nut
@@ -0,0 +1,44 @@
+GUI <- {}
+
+enum Orientation
+{
+ Horizontal,
+ Vertical
+}
+
+enum Align
+{
+ Center,
+ Left,
+ Right
+}
+
+const DRAW_SHRINK_TO_FIT = false
+
+const TOOLTIP_INTERVAL = 500
+
+const RANGE_INDICATOR_SIZE = 25
+
+const SCROLLBAR_BUTTON_SIZE = 25
+const SCROLLBAR_DRAG_DISTANCE = 135
+
+const TAB_WIDTH = 100
+const TAB_HEIGHT = 33
+
+const GRIDLIST_SCROLLBAR_SIZE = 20
+
+//Global Events
+addEvent("GUI.onRender")
+addEvent("GUI.onClick")
+addEvent("GUI.onOpen")
+addEvent("GUI.onClose")
+
+//Main init func
+addEventHandler("onInit",function()
+{
+ enableEvent_Render(true)
+
+ //Information about the authors
+ print("## Gui Engine 2.0 successfully loaded ##")
+ print("- Author Tommy & Patrix")
+})
diff --git a/lib/gui-framework/multiple_inheritance.nut b/lib/gui-framework/multiple_inheritance.nut
new file mode 100644
index 0000000..f686770
--- /dev/null
+++ b/lib/gui-framework/multiple_inheritance.nut
@@ -0,0 +1,22 @@
+/*
+
+ Script: Multiple Inheritance
+ Author: Calysto Canem
+
+*/
+
+function classes(...)
+{
+ local c = class extends vargv[0] {}
+
+ for (local i = 1, end = vargv.len(); i < end; ++i)
+ {
+ foreach (name, value in vargv[i])
+ {
+ if (name != "constructor")
+ c[name] <- value
+ }
+ }
+
+ return c
+}
diff --git a/lib/gui-framework/utility.nut b/lib/gui-framework/utility.nut
new file mode 100644
index 0000000..04eea66
--- /dev/null
+++ b/lib/gui-framework/utility.nut
@@ -0,0 +1,109 @@
+///////////////
+// Functions
+///////////////
+
+/*
+ getResolutionChangedScale
+*/
+
+local oldResolution = getResolution()
+local newResolution = getResolution()
+
+addEventHandler("onChangeResolution", function()
+{
+ oldResolution = newResolution
+ newResolution = getResolution()
+})
+
+function getResolutionChangedScale()
+{
+ local result =
+ {
+ x = newResolution.x.tofloat() / oldResolution.x.tofloat(),
+ y = newResolution.y.tofloat() / oldResolution.y.tofloat()
+ }
+
+ return result
+}
+
+/*
+ getFrameTime
+*/
+
+local before = getTickCount()
+
+addEventHandler("onInit", function()
+{
+ addEventHandler("onRender", function()
+ {
+ before = getTickCount()
+ })
+})
+
+function getFrameTime()
+{
+ return getTickCount() - before
+}
+
+function getFrameTimeF()
+{
+ return getFrameTime() / 1000.0
+}
+
+/*
+ textHeight
+*/
+
+local draw = Draw(0, 0, "")
+draw.font = "FONT_OLD_10_WHITE_HI.TGA"
+
+local _textSetFont = textSetFont
+
+function textSetFont(font)
+{
+ draw.font = font
+ _textSetFont(font)
+}
+
+function textHeightPx(text)
+{
+ draw.text = text
+
+ local result = draw.heightPx
+ draw.text = ""
+
+ return result
+}
+
+function textHeight(text)
+{
+ return nay(textHeightPx(text))
+}
+
+///////////////
+// Events
+///////////////
+
+/*
+ onMouseMove event
+*/
+
+addEvent("onMouseMove")
+
+local oldCursorPosition = getCursorPositionPx()
+
+addEventHandler("onRender", function()
+{
+ if (!isCursorVisible())
+ return
+
+ local cursorPosition = getCursorPositionPx()
+
+ if (cursorPosition.x == oldCursorPosition.x && cursorPosition.y == oldCursorPosition.y)
+ return
+
+ callEvent("onMouseMove", cursorPosition.x, cursorPosition.y, oldCursorPosition.x, oldCursorPosition.y)
+
+ oldCursorPosition.x = cursorPosition.x
+ oldCursorPosition.y = cursorPosition.y
+})
diff --git a/lib/gui-framework/vector.nut b/lib/gui-framework/vector.nut
new file mode 100644
index 0000000..b502662
--- /dev/null
+++ b/lib/gui-framework/vector.nut
@@ -0,0 +1,11 @@
+class GUI.Vector2D
+{
+ constructor(_x, _y)
+ {
+ x = _x;
+ y = _y;
+ }
+
+ x = 0;
+ y = 0;
+};
\ No newline at end of file