mirror of
https://github.com/Qsgs-Fans/FreeKill.git
synced 2024-11-16 11:42:45 +08:00
parent
4ad61cf70f
commit
139464be14
|
@ -1,6 +1,6 @@
|
||||||
cmake_minimum_required(VERSION 3.16)
|
cmake_minimum_required(VERSION 3.16)
|
||||||
|
|
||||||
project(FreeKill VERSION 0.0.4)
|
project(FreeKill VERSION 0.0.6)
|
||||||
add_definitions(-DFK_VERSION=\"${CMAKE_PROJECT_VERSION}\")
|
add_definitions(-DFK_VERSION=\"${CMAKE_PROJECT_VERSION}\")
|
||||||
|
|
||||||
if (NOT ${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
|
if (NOT ${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="org.notify.FreeKill"
|
package="org.notify.FreeKill"
|
||||||
android:installLocation="preferExternal"
|
android:installLocation="preferExternal"
|
||||||
android:versionCode="4"
|
android:versionCode="6"
|
||||||
android:versionName="0.0.4">
|
android:versionName="0.0.6">
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
rm -rf res assets
|
rm -rf res/mipmap assets
|
||||||
|
|
||||||
if [ ! -e res/mipmap ]; then
|
if [ ! -e res/mipmap ]; then
|
||||||
mkdir -p res/mipmap
|
mkdir -p res/mipmap
|
||||||
|
|
BIN
image/lady.png
Normal file
BIN
image/lady.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 208 KiB |
BIN
image/lobby/profile.png
Normal file
BIN
image/lobby/profile.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 34 KiB |
BIN
image/widelogo.png
Normal file
BIN
image/widelogo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.0 KiB |
|
@ -36,8 +36,8 @@
|
||||||
<translation>用户名</translation>
|
<translation>用户名</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Password</source>
|
<source>Show Password</source>
|
||||||
<translation>密码</translation>
|
<translation>显示密码</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Join Server</source>
|
<source>Join Server</source>
|
||||||
|
@ -51,12 +51,56 @@
|
||||||
<source>PackageManage</source>
|
<source>PackageManage</source>
|
||||||
<translation>管理拓展包</translation>
|
<translation>管理拓展包</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Welcome back!</source>
|
||||||
|
<translation>欢迎回来!</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Server Addr</source>
|
||||||
|
<translation>服务器IP</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>FAQ</source>
|
||||||
|
<translation>常见疑问</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>$LoginFAQ</source>
|
||||||
|
<translation>
|
||||||
|
登录过程中的常见问题:
|
||||||
|
|
||||||
|
1. 怎么联机?
|
||||||
|
将服务器IP输入到指定区域,然后填用户名和密码即可加入服务器。
|
||||||
|
|
||||||
|
2. 怎么注册?
|
||||||
|
无需注册,只要填写好用户名和密码,服务器就会自动为您注册。你的用户名和密码保存在服务端,下次登入还是需要输入一样的用户名和密码。但是无需担心,FK会自动为你记住密码。
|
||||||
|
</translation>
|
||||||
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>updated packages for md5</source>
|
<source>updated packages for md5</source>
|
||||||
<translation>已为您与服务器同步拓展包,请尝试再次连入</translation>
|
<translation>已为您与服务器同步拓展包,请尝试再次连入</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
|
||||||
|
<context>
|
||||||
|
<name>Splash</name>
|
||||||
|
<message>
|
||||||
|
<source>Free</source>
|
||||||
|
<translation>自由</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Open</source>
|
||||||
|
<translation>开放</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Flexible</source>
|
||||||
|
<translation>可拓展</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Press Any Key...</source>
|
||||||
|
<translation>请按任意键...</translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
|
|
||||||
<context>
|
<context>
|
||||||
<name>Logic</name>
|
<name>Logic</name>
|
||||||
<message>
|
<message>
|
||||||
|
|
|
@ -14,11 +14,13 @@ Fk:loadTranslationTable{
|
||||||
["Lobby BG"] = "大厅壁纸",
|
["Lobby BG"] = "大厅壁纸",
|
||||||
["Room BG"] = "房间背景",
|
["Room BG"] = "房间背景",
|
||||||
["Game BGM"] = "游戏BGM",
|
["Game BGM"] = "游戏BGM",
|
||||||
|
["Poster Girl"] = "看板娘",
|
||||||
|
|
||||||
["Create Room"] = "创建房间",
|
["Create Room"] = "创建房间",
|
||||||
["Room Name"] = "房间名字",
|
["Room Name"] = "房间名字",
|
||||||
["$RoomName"] = "%1的房间",
|
["$RoomName"] = "%1的房间",
|
||||||
["Player num"] = "玩家数目",
|
["Player num"] = "玩家数目",
|
||||||
|
["Select general num"] = "选将数目",
|
||||||
["Game Mode"] = "游戏模式",
|
["Game Mode"] = "游戏模式",
|
||||||
["Enable free assign"] = "自由选将",
|
["Enable free assign"] = "自由选将",
|
||||||
["General Settings"] = "通常设置",
|
["General Settings"] = "通常设置",
|
||||||
|
@ -31,33 +33,67 @@ Fk:loadTranslationTable{
|
||||||
["Scenarios Overview"] = "玩法一览",
|
["Scenarios Overview"] = "玩法一览",
|
||||||
["Replay"] = "录像",
|
["Replay"] = "录像",
|
||||||
["About"] = "关于",
|
["About"] = "关于",
|
||||||
["about_freekill_description"] = "<b>关于FreeKill</b><br/>" ..
|
["about_freekill_description"] = [[
|
||||||
"以便于DIY为首要目的的开源三国杀游戏。<br/>" ..
|
# 关于FreeKill
|
||||||
"<br/>项目链接: https://github.com/Notify-ctrl/FreeKill",
|
|
||||||
["about_qt_description"] = "<b>关于Qt</b><br/>" ..
|
以便于DIY为首要目的的开源三国杀游戏。
|
||||||
"Qt是一个C++图形界面应用程序开发框架,拥有强大的跨平台能力以及易于使用的API。<br/>" ..
|
|
||||||
"<br/>本程序使用Qt 6.2+,主要利用QtQuick开发UI,同时也使用Qt的网络库开发服务端程序。<br/>" ..
|
项目链接: https://github.com/Notify-ctrl/FreeKill
|
||||||
"<br/>官网: https://www.qt.io",
|
]],
|
||||||
["about_lua_description"] = "<b>关于Lua</b><br/>" ..
|
["about_qt_description"] = [[
|
||||||
"Lua是一种小巧、灵活、高效的脚本语言,广泛用于游戏开发中。<br/>" ..
|
# 关于Qt
|
||||||
"<br/>本程序使用Lua 5.4,利用其完全实现了整个游戏逻辑。<br/>" ..
|
|
||||||
"<br/>官网: https://www.lua.org",
|
Qt是一个C++图形界面应用程序开发框架,拥有强大的跨平台能力以及易于使用的API。
|
||||||
["about_ossl_description"] = "<b>关于OpenSSL</b><br/>" ..
|
|
||||||
"OpenSSL是一个开源包,用来提供安全通信与各种加密支持。<br/>" ..
|
本程序使用Qt 6.2+,主要利用QtQuick开发UI,同时也使用Qt的网络库开发服务端程序。
|
||||||
"<br/>本程序目前用到了crypto库,以获得RSA加密算法支持。<br/>" ..
|
|
||||||
"<br/>官网: https://www.openssl.org",
|
官网: https://www.qt.io
|
||||||
["about_gplv3_description"] = "<b>关于GPLv3</b><br/>" ..
|
]],
|
||||||
"GNU通用公共许可协议(简称GPL)是一个广泛使用的自由软件许可证条款,它确保广大用户自由地使用、学习、共享或修改软件。<br/>" ..
|
["about_lua_description"] = [[
|
||||||
"<br/>由于Qt是按照GPLv3协议开源的库,与此同时本程序用到的readline库也属于GPLv3库,再加上QSanguosha也是以GPLv3协议开源的软件(从中借鉴了不少代码和思路),因此这个项目也使用GPLv3协议开源。<br/>" ..
|
# 关于Lua
|
||||||
"<br/>官网: https://gplv3.fsf.org",
|
|
||||||
["about_sqlite_description"] = "<b>关于SQLite</b><br/>" ..
|
Lua是一种小巧、灵活、高效的脚本语言,广泛用于游戏开发中。
|
||||||
"SQLite是一个轻量级的数据库,具有占用资源低、运行效率快、嵌入性好等优点。<br/>" ..
|
|
||||||
"<br/>FreeKill使用sqlite3在服务端保存用户的各种信息。<br/>" ..
|
本程序使用Lua 5.4,利用其完全实现了整个游戏逻辑。
|
||||||
"<br/>官网: https://www.sqlite.org",
|
|
||||||
["about_git2_description"] = "<b>关于Libgit2</b><br/>" ..
|
官网: https://www.lua.org
|
||||||
"Libgit2是一个轻量级的、跨平台的、纯C实现的库,支持Git的大部分核心操作,并且支持几乎任何能与C语言交互的编程语言。<br/>" ..
|
]],
|
||||||
"<br/>FreeKill使用的是libgit2的C API,与此同时使用Git完成拓展包的下载、更新、管理等等功能。<br/>" ..
|
["about_ossl_description"] = [[
|
||||||
"<br/>官网: https://libgit2.org",
|
# 关于OpenSSL
|
||||||
|
|
||||||
|
OpenSSL是一个开源包,用来提供安全通信与各种加密支持。
|
||||||
|
|
||||||
|
本程序目前用到了crypto库,以获得RSA加密算法支持。
|
||||||
|
|
||||||
|
官网: https://www.openssl.org
|
||||||
|
]],
|
||||||
|
["about_gplv3_description"] = [[
|
||||||
|
# 关于GPLv3
|
||||||
|
|
||||||
|
GNU通用公共许可协议(简称GPL)是一个广泛使用的自由软件许可证条款,它确保广大用户自由地使用、学习、共享或修改软件。
|
||||||
|
|
||||||
|
由于Qt是按照GPLv3协议开源的库,与此同时本程序用到的readline库也属于GPLv3库,再加上QSanguosha也是以GPLv3协议开源的软件(从中借鉴了不少代码和思路),因此这个项目也使用GPLv3协议开源。
|
||||||
|
|
||||||
|
官网: https://gplv3.fsf.org
|
||||||
|
]],
|
||||||
|
["about_sqlite_description"] = [[
|
||||||
|
# 关于SQLite
|
||||||
|
|
||||||
|
SQLite是一个轻量级的数据库,具有占用资源低、运行效率快、嵌入性好等优点。
|
||||||
|
|
||||||
|
FreeKill使用sqlite3在服务端保存用户的各种信息。
|
||||||
|
|
||||||
|
官网: https://www.sqlite.org
|
||||||
|
]],
|
||||||
|
["about_git2_description"] = [[
|
||||||
|
# 关于Libgit2
|
||||||
|
|
||||||
|
Libgit2是一个轻量级的、跨平台的、纯C实现的库,支持Git的大部分核心操作,并且支持几乎任何能与C语言交互的编程语言。
|
||||||
|
|
||||||
|
FreeKill使用的是libgit2的C API,与此同时使用Git完成拓展包的下载、更新、管理等等功能。
|
||||||
|
|
||||||
|
官网: https://libgit2.org
|
||||||
|
]],
|
||||||
|
|
||||||
["Exit Lobby"] = "退出大厅",
|
["Exit Lobby"] = "退出大厅",
|
||||||
|
|
||||||
|
@ -114,6 +150,7 @@ Fk:loadTranslationTable{
|
||||||
|
|
||||||
["$GameOver"] = "游戏结束",
|
["$GameOver"] = "游戏结束",
|
||||||
["$Winner"] = "%1 获胜",
|
["$Winner"] = "%1 获胜",
|
||||||
|
["$NoWinner"] = "平局!",
|
||||||
["Back To Lobby"] = "返回大厅",
|
["Back To Lobby"] = "返回大厅",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -67,6 +67,7 @@ end
|
||||||
|
|
||||||
function GameLogic:chooseGenerals()
|
function GameLogic:chooseGenerals()
|
||||||
local room = self.room
|
local room = self.room
|
||||||
|
local generalNum = room.settings.generalNum
|
||||||
local function setPlayerGeneral(player, general)
|
local function setPlayerGeneral(player, general)
|
||||||
if Fk.generals[general] == nil then return end
|
if Fk.generals[general] == nil then return end
|
||||||
player.general = general
|
player.general = general
|
||||||
|
@ -78,7 +79,7 @@ function GameLogic:chooseGenerals()
|
||||||
local lord_general = nil
|
local lord_general = nil
|
||||||
if lord ~= nil then
|
if lord ~= nil then
|
||||||
room.current = lord
|
room.current = lord
|
||||||
local generals = Fk:getGeneralsRandomly(3)
|
local generals = Fk:getGeneralsRandomly(generalNum)
|
||||||
for i = 1, #generals do
|
for i = 1, #generals do
|
||||||
generals[i] = generals[i].name
|
generals[i] = generals[i].name
|
||||||
end
|
end
|
||||||
|
@ -88,14 +89,13 @@ function GameLogic:chooseGenerals()
|
||||||
end
|
end
|
||||||
|
|
||||||
local nonlord = room:getOtherPlayers(lord, true)
|
local nonlord = room:getOtherPlayers(lord, true)
|
||||||
local generals = Fk:getGeneralsRandomly(#nonlord * 3, nil, {lord_general})
|
local generals = Fk:getGeneralsRandomly(#nonlord * generalNum, nil, {lord_general})
|
||||||
table.shuffle(generals)
|
table.shuffle(generals)
|
||||||
for _, p in ipairs(nonlord) do
|
for _, p in ipairs(nonlord) do
|
||||||
local arg = {
|
local arg = {}
|
||||||
(table.remove(generals, 1)).name,
|
for i = 1, generalNum do
|
||||||
(table.remove(generals, 1)).name,
|
table.insert(arg, table.remove(generals, 1).name)
|
||||||
(table.remove(generals, 1)).name,
|
end
|
||||||
}
|
|
||||||
p.request_data = json.encode(arg)
|
p.request_data = json.encode(arg)
|
||||||
p.default_reply = arg[1]
|
p.default_reply = arg[1]
|
||||||
end
|
end
|
||||||
|
|
|
@ -87,6 +87,11 @@ function Room:initialize(_room)
|
||||||
|
|
||||||
-- If ret == true, then when err_msg is true, that means no request
|
-- If ret == true, then when err_msg is true, that means no request
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if not self.game_finished then
|
||||||
|
self:doBroadcastNotify("GameOver", "")
|
||||||
|
self.room:gameOver()
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
self.players = {}
|
self.players = {}
|
||||||
|
@ -274,6 +279,9 @@ function Room:getNCards(num, from)
|
||||||
while num > 0 do
|
while num > 0 do
|
||||||
if #self.draw_pile < 1 then
|
if #self.draw_pile < 1 then
|
||||||
self:shuffleDrawPile()
|
self:shuffleDrawPile()
|
||||||
|
if #self.draw_pile < 1 then
|
||||||
|
self:gameOver("")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local index = from == "top" and 1 or #self.draw_pile
|
local index = from == "top" and 1 or #self.draw_pile
|
||||||
|
|
|
@ -6,7 +6,7 @@ local function getWinner(victim)
|
||||||
|
|
||||||
if victim.role == "lord" then
|
if victim.role == "lord" then
|
||||||
if #alive == 1 and alive[1].role == "renegade" then
|
if #alive == 1 and alive[1].role == "renegade" then
|
||||||
winner = "renegede"
|
winner = "renegade"
|
||||||
else
|
else
|
||||||
winner = "rebel"
|
winner = "rebel"
|
||||||
end
|
end
|
||||||
|
|
|
@ -137,6 +137,171 @@ Fk:loadTranslationTable{
|
||||||
[":biyue"] = "结束阶段开始时,你可以摸一张牌。",
|
[":biyue"] = "结束阶段开始时,你可以摸一张牌。",
|
||||||
|
|
||||||
["aaa_role_mode"] = "身份模式",
|
["aaa_role_mode"] = "身份模式",
|
||||||
|
[":aaa_role_mode"] = [========================================[
|
||||||
|
# 身份模式简介
|
||||||
|
|
||||||
|
___
|
||||||
|
|
||||||
|
(原文地址: https://sgs.52pk.com/zl/201205/5299813.shtml )
|
||||||
|
|
||||||
|
你即将开始学习一款集角色扮演、战斗、伪装等要素于一体的多人卡牌游戏。它能让你通过扮演耳熟能详的三国角色,在颠覆性的历史舞台中,演义一段扑朔迷离并充满刺激的较量。你将会充分体验到与玩家博弈的乐趣,它将是你聚会休闲的最佳伙伴,它就是――三国杀。
|
||||||
|
|
||||||
|
___
|
||||||
|
|
||||||
|
## 游戏配件
|
||||||
|
|
||||||
|
游戏需要用到的牌为:身份牌,体力牌,武将牌,游戏牌。
|
||||||
|
|
||||||
|
身份牌8张:1主公,2忠臣,4反贼,1内奸;武将牌25张;游戏牌104张+EX游戏牌4张;体力牌8张。
|
||||||
|
|
||||||
|
___
|
||||||
|
|
||||||
|
## 游戏目标
|
||||||
|
|
||||||
|
玩家的游戏目标是由拿到的身份牌决定的,每种身份的胜利条件如下:
|
||||||
|
|
||||||
|
- 主公:消灭所有的反贼和内奸,平定天下。
|
||||||
|
- 忠臣:不惜一切代价保护主公,胜利条件与主公相同。
|
||||||
|
- 反贼:杀死主公,推翻统治。
|
||||||
|
- 内奸:除掉除自己之外的所有人,成为最后的生还者。
|
||||||
|
|
||||||
|
___
|
||||||
|
|
||||||
|
## 决定身份
|
||||||
|
|
||||||
|
参考下表,抽取等于玩家人数的身份牌:
|
||||||
|
|
||||||
|
| 玩家人数 | 主公 | 忠臣 | 反贼 | 内奸 |
|
||||||
|
| -------- | ---- | ---- | ---- | ---- |
|
||||||
|
| 2 | 1 | 0 | 1 | 0 |
|
||||||
|
| 3 | 1 | 0 | 1 | 1 |
|
||||||
|
| 4 | 1 | 1 | 1 | 1 |
|
||||||
|
| 5 | 1 | 1 | 2 | 1 |
|
||||||
|
| 6 | 1 | 1 | 3 | 1 |
|
||||||
|
| 7 | 1 | 2 | 3 | 1 |
|
||||||
|
| 8 | 1 | 2 | 4 | 1 |
|
||||||
|
|
||||||
|
随机分给每个玩家一张身份牌,抽到主公身份的玩家需立即亮出身份(将主公牌正面朝上放在面前),其它身份的玩家保存好自己的身份牌,不让别的玩家知道自己的身份。
|
||||||
|
|
||||||
|
___
|
||||||
|
|
||||||
|
## 挑选武将
|
||||||
|
|
||||||
|
带有特殊能力的武将牌为游戏提供了丰富的变化和乐趣,但同时也让游戏变得相对复杂,如果是第一次玩三国杀,建议暂且不使用武将牌。请略过这部分,继续看“分发体力牌”。若对三国杀已经有了大致的了解,可以尝试加入武将进行游戏,按如下的步骤挑选武将。
|
||||||
|
|
||||||
|
首先分给获得主公身份的玩家(以下简称主公玩家)“曹操”、“刘备”、“孙权”,和另外随机抽取的2张武将牌,一共5张武将牌。由主公玩家挑选一个武将扮演,并将选好的武将牌展示给其他玩家。
|
||||||
|
|
||||||
|
将剩余的24张武将牌洗混,随机发给其余每位玩家各3张(10人游戏时每人发2张)。接着每人从3张牌里挑选一张扣在自己面前,待所有玩家都挑选好后同时亮出。将剩余未选的武将牌洗混,面朝下放在一旁。
|
||||||
|
|
||||||
|
___
|
||||||
|
|
||||||
|
## 分发体力牌
|
||||||
|
|
||||||
|
拿取对应人物体力上限的体力牌(看阴阳鱼的数量),用武将牌盖住左侧。
|
||||||
|
|
||||||
|
主公在其体力上限的基础上再增加一点(四人游戏时不再额外增加)。
|
||||||
|
|
||||||
|
例如三点体力的角色当主公时,他/她的体力上限就是四点,使用四点体力的体力牌。
|
||||||
|
|
||||||
|
将体力牌置于武将牌下方,露出当前体力值。扣减体力时,将武将牌右移挡住被扣减的体力。
|
||||||
|
|
||||||
|
___
|
||||||
|
|
||||||
|
## 回合流程
|
||||||
|
|
||||||
|
将游戏牌洗混,随机分给每个玩家4张,此为起始手牌(手牌:拿在手里的牌)。
|
||||||
|
|
||||||
|
将剩余游戏牌放在桌子中央,作为牌堆(玩家在游戏中弃置的牌放在一旁,组成弃牌堆,弃牌堆里的牌全部正面朝上放置)。
|
||||||
|
|
||||||
|
进行游戏时,由主公开始,按逆时针方向以回合的方式进行。
|
||||||
|
|
||||||
|
即:每名玩家有一个自己的回合,一名玩家回合结束后,其右边玩家的回合开始,依次轮流进行。
|
||||||
|
|
||||||
|
每个玩家的回合可以分为六个阶段:
|
||||||
|
|
||||||
|
1. 准备阶段
|
||||||
|
|
||||||
|
2. 判定阶段
|
||||||
|
|
||||||
|
3. 摸牌阶段
|
||||||
|
|
||||||
|
4. 出牌阶段
|
||||||
|
|
||||||
|
5. 弃牌阶段
|
||||||
|
|
||||||
|
6. 结束阶段
|
||||||
|
|
||||||
|
下面对这几个阶段进行描述:
|
||||||
|
|
||||||
|
### 准备阶段
|
||||||
|
|
||||||
|
通常可以跳过,有些武将可以使用此阶段的技能。
|
||||||
|
|
||||||
|
### 判定阶段
|
||||||
|
|
||||||
|
若你的面前横置着延时类锦囊,你必须依次对这些延时类锦囊进行判定。
|
||||||
|
|
||||||
|
*若你的面前横置有两种或更多的延时类锦囊,你从最后一个施加给你的锦囊开始判定(最早放置的最后判定)。*
|
||||||
|
|
||||||
|
### 摸牌阶段
|
||||||
|
|
||||||
|
你从牌堆顶摸两张牌。
|
||||||
|
|
||||||
|
*在游戏里,若没有特殊说明,“摸…张牌”指的就是从牌堆最上方摸牌。*
|
||||||
|
|
||||||
|
*当需要摸牌或将要对牌堆产生影响时,牌堆没牌,则立即将弃牌堆洗混后形成新的摸牌堆。*
|
||||||
|
|
||||||
|
### 出牌阶段
|
||||||
|
|
||||||
|
你可以使用0到任意张牌,加强自己或攻击他人,但必须遵守以下两条规则:
|
||||||
|
|
||||||
|
1. 每个出牌阶段仅限使用一次【杀】。
|
||||||
|
|
||||||
|
2. 任何一个玩家面前的判定区或装备区里不能放有两张同名的牌。
|
||||||
|
|
||||||
|
每使用一张牌,即执行该牌之效果,详见“游戏牌详解”。如无特殊说明,游戏牌在使用后均需弃置(放入弃牌堆)。
|
||||||
|
|
||||||
|
### 弃牌阶段
|
||||||
|
|
||||||
|
在出牌阶段中,不想出或没法出牌时,就进入弃牌阶段,此时检查你的手牌数是否超出你当前的体力值(你的手牌上限等于你当前的体力值),每超出一张,需要弃一张手牌。
|
||||||
|
|
||||||
|
### 结束阶段
|
||||||
|
|
||||||
|
通常可以跳过,有些武将可以使用此阶段的技能。
|
||||||
|
|
||||||
|
___
|
||||||
|
|
||||||
|
## 补充说明
|
||||||
|
|
||||||
|
1. 在游戏里,若无特殊说明,摸牌即是说从游戏牌堆顶摸牌。
|
||||||
|
|
||||||
|
2. 玩家在游戏中使用、打出或弃置的游戏牌放在一旁,组成弃牌堆,弃牌堆里的牌全部正面朝上放置。
|
||||||
|
|
||||||
|
3. 当牌堆没牌时,则立即将弃牌堆洗混后形成新的牌堆。
|
||||||
|
|
||||||
|
4. “体力上限”与“当前体力值”不一样,请注意区别。
|
||||||
|
|
||||||
|
___
|
||||||
|
|
||||||
|
## 武将死亡
|
||||||
|
|
||||||
|
当一个武将的体力降到0或更低时,即进入濒死状态,除非自己或他人在此时用【桃】来挽救该武将,否则该武将死亡。武将死亡后,弃置该武将所有牌及判定区里的牌,并亮出身份牌。
|
||||||
|
|
||||||
|
任何人杀死一名反贼(即凶手也是反贼),立即摸三张牌。
|
||||||
|
|
||||||
|
若主公杀死了忠臣,主公需要立即弃掉所有手牌和已装备的牌。
|
||||||
|
|
||||||
|
___
|
||||||
|
|
||||||
|
## 游戏结束
|
||||||
|
|
||||||
|
当以下任意一种情况发生时,游戏立即结束:
|
||||||
|
|
||||||
|
1、主公被杀。此时若内奸是唯一存活的角色(有且仅有一名内奸存活),则内奸获胜,除此之外的情况为反贼获胜(不论反贼角色死活)。
|
||||||
|
|
||||||
|
2、所有的反贼和内奸都已死亡:主公和忠臣(不论死活)都获胜。
|
||||||
|
|
||||||
|
]========================================],
|
||||||
}
|
}
|
||||||
|
|
||||||
-- aux skills
|
-- aux skills
|
||||||
|
|
|
@ -16,6 +16,8 @@ QtObject {
|
||||||
property var disabledPack: []
|
property var disabledPack: []
|
||||||
property string preferedMode
|
property string preferedMode
|
||||||
property int preferedPlayerNum
|
property int preferedPlayerNum
|
||||||
|
property int preferredGeneralNum
|
||||||
|
property string ladyImg
|
||||||
|
|
||||||
// Player property of client
|
// Player property of client
|
||||||
property string serverAddr
|
property string serverAddr
|
||||||
|
@ -44,6 +46,8 @@ QtObject {
|
||||||
disabledPack = conf.disabledPack || [ "test_p_0" ];
|
disabledPack = conf.disabledPack || [ "test_p_0" ];
|
||||||
preferedMode = conf.preferedMode || "aaa_role_mode";
|
preferedMode = conf.preferedMode || "aaa_role_mode";
|
||||||
preferedPlayerNum = conf.preferedPlayerNum || 2;
|
preferedPlayerNum = conf.preferedPlayerNum || 2;
|
||||||
|
preferredGeneralNum = conf.preferredGeneralNum || 3;
|
||||||
|
ladyImg = conf.ladyImg || AppPath + "/image/lady";
|
||||||
}
|
}
|
||||||
|
|
||||||
function saveConf() {
|
function saveConf() {
|
||||||
|
@ -60,6 +64,8 @@ QtObject {
|
||||||
conf.disabledPack = disabledPack;
|
conf.disabledPack = disabledPack;
|
||||||
conf.preferedMode = preferedMode;
|
conf.preferedMode = preferedMode;
|
||||||
conf.preferedPlayerNum = preferedPlayerNum;
|
conf.preferedPlayerNum = preferedPlayerNum;
|
||||||
|
conf.ladyImg = ladyImg;
|
||||||
|
conf.preferredGeneralNum = preferredGeneralNum;
|
||||||
|
|
||||||
Backend.saveConf(JSON.stringify(conf, undefined, 2));
|
Backend.saveConf(JSON.stringify(conf, undefined, 2));
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ Item {
|
||||||
Item {
|
Item {
|
||||||
Rectangle {
|
Rectangle {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
color: "#88888888"
|
color: "#88EEEEEE"
|
||||||
radius: 2
|
radius: 2
|
||||||
width: root.width * 0.8
|
width: root.width * 0.8
|
||||||
height: root.height * 0.8
|
height: root.height * 0.8
|
||||||
|
@ -50,7 +50,7 @@ Item {
|
||||||
width: parent.width * 0.65
|
width: parent.width * 0.65
|
||||||
text: Backend.translate("about_" + dest + "_description")
|
text: Backend.translate("about_" + dest + "_description")
|
||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
textFormat: Text.RichText
|
textFormat: Text.MarkdownText
|
||||||
font.pixelSize: 18
|
font.pixelSize: 18
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,92 +1,179 @@
|
||||||
import QtQuick
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
Frame {
|
Item {
|
||||||
id: join_server
|
width: 960 * 0.8
|
||||||
|
height: 540 * 0.8
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
scale: 1.5
|
|
||||||
background: Rectangle {
|
Item {
|
||||||
color: "#88888888"
|
id: left
|
||||||
radius: 2
|
width: 300
|
||||||
|
height: parent.height
|
||||||
|
|
||||||
|
Image {
|
||||||
|
id: lady
|
||||||
|
width: parent.width + 20
|
||||||
|
height: parent.height
|
||||||
|
fillMode: Image.PreserveAspectFit
|
||||||
|
}
|
||||||
|
|
||||||
|
Image {
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.bottomMargin: 12
|
||||||
|
width: parent.width
|
||||||
|
source: AppPath + "/image/widelogo"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Column {
|
Rectangle {
|
||||||
spacing: 8
|
id: right
|
||||||
ComboBox {
|
anchors.left: left.right
|
||||||
id: server_addr
|
width: parent.width - left.width
|
||||||
model: []
|
height: parent.height
|
||||||
editable: true
|
color: "#88EEEEEE"
|
||||||
|
radius: 16
|
||||||
|
|
||||||
onEditTextChanged: {
|
ColumnLayout {
|
||||||
if (model.indexOf(editText) === -1) {
|
width: parent.width * 0.8
|
||||||
passwordEdit.text = "";
|
height: parent.height * 0.8
|
||||||
} else {
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
let data = config.savedPassword[editText];
|
anchors.top: parent.top
|
||||||
screenNameEdit.text = data.username;
|
anchors.topMargin: 40
|
||||||
passwordEdit.text = data.shorten_password;
|
//spacing
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: qsTr("Welcome back!")
|
||||||
|
font.pixelSize: 28
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
GridLayout {
|
||||||
|
columns: 2
|
||||||
|
rowSpacing: 20
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: qsTr("Server Addr")
|
||||||
|
}
|
||||||
|
ComboBox {
|
||||||
|
id: server_addr
|
||||||
|
Layout.fillWidth: true
|
||||||
|
model: []
|
||||||
|
editable: true
|
||||||
|
|
||||||
|
onEditTextChanged: {
|
||||||
|
if (model.indexOf(editText) === -1) {
|
||||||
|
passwordEdit.text = "";
|
||||||
|
} else {
|
||||||
|
let data = config.savedPassword[editText];
|
||||||
|
screenNameEdit.text = data.username;
|
||||||
|
passwordEdit.text = data.shorten_password;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: qsTr("Username")
|
||||||
|
}
|
||||||
|
TextField {
|
||||||
|
id: screenNameEdit
|
||||||
|
Layout.fillWidth: true
|
||||||
|
placeholderText: qsTr("Username")
|
||||||
|
text: ""
|
||||||
|
onTextChanged: {
|
||||||
|
passwordEdit.text = "";
|
||||||
|
let data = config.savedPassword[server_addr.editText];
|
||||||
|
if (data) {
|
||||||
|
if (text === data.username) {
|
||||||
|
passwordEdit.text = data.shorten_password;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CheckBox {
|
||||||
|
id: showPasswordCheck
|
||||||
|
text: qsTr("Show Password")
|
||||||
|
}
|
||||||
|
TextField {
|
||||||
|
id: passwordEdit
|
||||||
|
Layout.fillWidth: true
|
||||||
|
placeholderText: qsTr("Password")
|
||||||
|
text: ""
|
||||||
|
echoMode: showPasswordCheck.checked ? TextInput.Normal : TextInput.Password
|
||||||
|
passwordCharacter: "*"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
TextField {
|
Button {
|
||||||
id: screenNameEdit
|
text: qsTr("Join Server")
|
||||||
placeholderText: qsTr("Username")
|
Layout.fillWidth: true
|
||||||
text: ""
|
enabled: passwordEdit.text !== ""
|
||||||
onTextChanged: {
|
onClicked: {
|
||||||
passwordEdit.text = "";
|
config.serverAddr = server_addr.editText;
|
||||||
let data = config.savedPassword[server_addr.editText];
|
config.screenName = screenNameEdit.text;
|
||||||
if (data) {
|
config.password = passwordEdit.text;
|
||||||
if (text === data.username) {
|
mainWindow.busy = true;
|
||||||
passwordEdit.text = data.shorten_password;
|
Backend.joinServer(server_addr.editText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Button {
|
||||||
|
Layout.preferredWidth: 180
|
||||||
|
text: qsTr("Console start")
|
||||||
|
enabled: passwordEdit.text !== ""
|
||||||
|
onClicked: {
|
||||||
|
config.serverAddr = "127.0.0.1";
|
||||||
|
config.screenName = screenNameEdit.text;
|
||||||
|
config.password = passwordEdit.text;
|
||||||
|
mainWindow.busy = true;
|
||||||
|
Backend.startServer(9527);
|
||||||
|
Backend.joinServer("127.0.0.1");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: qsTr("PackageManage")
|
||||||
|
onClicked: {
|
||||||
|
mainStack.push(packageManage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*TextField {
|
|
||||||
id: avatarEdit
|
|
||||||
text: "liubei"
|
|
||||||
}*/
|
|
||||||
TextField {
|
|
||||||
id: passwordEdit
|
|
||||||
placeholderText: qsTr("Password")
|
|
||||||
text: ""
|
|
||||||
echoMode: TextInput.Password
|
|
||||||
passwordCharacter: "*"
|
|
||||||
}
|
|
||||||
Button {
|
|
||||||
text: qsTr("Join Server")
|
|
||||||
enabled: passwordEdit.text !== ""
|
|
||||||
onClicked: {
|
|
||||||
config.serverAddr = server_addr.editText;
|
|
||||||
config.screenName = screenNameEdit.text;
|
|
||||||
config.password = passwordEdit.text;
|
|
||||||
mainWindow.busy = true;
|
|
||||||
Backend.joinServer(server_addr.editText);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Button {
|
|
||||||
text: qsTr("Console start")
|
|
||||||
enabled: passwordEdit.text !== ""
|
|
||||||
onClicked: {
|
|
||||||
config.serverAddr = "127.0.0.1";
|
|
||||||
config.screenName = screenNameEdit.text;
|
|
||||||
config.password = passwordEdit.text;
|
|
||||||
mainWindow.busy = true;
|
|
||||||
Backend.startServer(9527);
|
|
||||||
Backend.joinServer("127.0.0.1");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Button {
|
Text {
|
||||||
anchors.right: parent.right
|
anchors.left: parent.left
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
text: qsTr("PackageManage")
|
anchors.leftMargin: 12
|
||||||
onClicked: {
|
anchors.bottomMargin: 12
|
||||||
mainStack.push(packageManage);
|
text: "FreeKill " + FkVersion
|
||||||
|
font.pixelSize: 16
|
||||||
|
font.bold: true
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.rightMargin: 8
|
||||||
|
anchors.bottomMargin: 8
|
||||||
|
text: qsTr("FAQ")
|
||||||
|
color: "blue"
|
||||||
|
font.pixelSize: 24
|
||||||
|
font.underline: true
|
||||||
|
|
||||||
|
TapHandler {
|
||||||
|
onTapped: {
|
||||||
|
errDialog.txt = qsTr("$LoginFAQ");
|
||||||
|
errDialog.open();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,12 +183,17 @@ Item {
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
config.loadConf();
|
config.loadConf();
|
||||||
|
|
||||||
|
lady.source = config.ladyImg;
|
||||||
|
|
||||||
server_addr.model = Object.keys(config.savedPassword);
|
server_addr.model = Object.keys(config.savedPassword);
|
||||||
server_addr.onModelChanged();
|
server_addr.onModelChanged();
|
||||||
server_addr.currentIndex = server_addr.model.indexOf(config.lastLoginServer);
|
server_addr.currentIndex = server_addr.model.indexOf(config.lastLoginServer);
|
||||||
|
|
||||||
let data = config.savedPassword[config.lastLoginServer];
|
let data = config.savedPassword[config.lastLoginServer];
|
||||||
screenNameEdit.text = data.username;
|
if (data) {
|
||||||
passwordEdit.text = data.shorten_password;
|
screenNameEdit.text = data.username;
|
||||||
|
passwordEdit.text = data.shorten_password;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import QtQuick.Window
|
import QtQuick.Window
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
|
import "LobbyElement"
|
||||||
import "Logic.js" as Logic
|
import "Logic.js" as Logic
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
|
@ -73,8 +74,13 @@ Item {
|
||||||
id: roomModel
|
id: roomModel
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PersonalSettings {
|
||||||
|
}
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
anchors.fill: parent
|
anchors.centerIn: parent
|
||||||
|
width: childrenRect.width
|
||||||
|
height: parent.height
|
||||||
Item {
|
Item {
|
||||||
Layout.preferredWidth: root.width * 0.6
|
Layout.preferredWidth: root.width * 0.6
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
|
@ -82,7 +88,7 @@ Item {
|
||||||
width: parent.width * 0.8
|
width: parent.width * 0.8
|
||||||
height: parent.height * 0.8
|
height: parent.height * 0.8
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
color: "#88888888"
|
color: "#88EEEEEE"
|
||||||
radius: 16
|
radius: 16
|
||||||
Text {
|
Text {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
|
@ -101,7 +107,7 @@ Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
GridLayout {
|
GridLayout {
|
||||||
flow: GridLayout.TopToBottom
|
flow: GridLayout.TopToBottom
|
||||||
rows: 4
|
rows: 4
|
||||||
|
@ -163,6 +169,57 @@ Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
Button {
|
||||||
|
text: Backend.translate("Create Room")
|
||||||
|
onClicked: {
|
||||||
|
lobby_dialog.source = "LobbyElement/CreateRoom.qml";
|
||||||
|
lobby_drawer.open();
|
||||||
|
config.observing = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Button {
|
||||||
|
text: Backend.translate("Generals Overview")
|
||||||
|
onClicked: {
|
||||||
|
mainStack.push(mainWindow.generalsOverviewPage);
|
||||||
|
mainStack.currentItem.loadPackages();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Button {
|
||||||
|
text: Backend.translate("Cards Overview")
|
||||||
|
onClicked: {
|
||||||
|
mainStack.push(mainWindow.cardsOverviewPage);
|
||||||
|
mainStack.currentItem.loadPackages();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Button {
|
||||||
|
text: Backend.translate("Scenarios Overview")
|
||||||
|
onClicked: {
|
||||||
|
mainStack.push(mainWindow.modesOverviewPage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Button {
|
||||||
|
text: Backend.translate("Replay")
|
||||||
|
}
|
||||||
|
Button {
|
||||||
|
text: Backend.translate("About")
|
||||||
|
onClicked: {
|
||||||
|
mainStack.push(mainWindow.aboutPage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Button {
|
||||||
|
text: Backend.translate("Exit Lobby")
|
||||||
|
onClicked: {
|
||||||
|
toast.show("Goodbye.");
|
||||||
|
Backend.quitLobby();
|
||||||
|
mainStack.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Drawer {
|
Drawer {
|
||||||
|
|
|
@ -9,7 +9,6 @@ Item {
|
||||||
signal finished()
|
signal finished()
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
spacing: 20
|
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
|
@ -142,6 +141,25 @@ Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
anchors.rightMargin: 8
|
||||||
|
spacing: 16
|
||||||
|
Text {
|
||||||
|
text: Backend.translate("Poster Girl")
|
||||||
|
}
|
||||||
|
TextField {
|
||||||
|
text: config.ladyImg
|
||||||
|
}
|
||||||
|
Button {
|
||||||
|
text: "..."
|
||||||
|
onClicked: {
|
||||||
|
fdialog.nameFilters = ["Image Files (*.jpg *.png)"];
|
||||||
|
fdialog.configKey = "ladyImg";
|
||||||
|
fdialog.open();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
anchors.rightMargin: 8
|
anchors.rightMargin: 8
|
||||||
spacing: 16
|
spacing: 16
|
||||||
|
|
54
qml/Pages/LobbyElement/PersonalSettings.qml
Normal file
54
qml/Pages/LobbyElement/PersonalSettings.qml
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import "../skin-bank.js" as SkinBank
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
width: bg.width
|
||||||
|
height: bg.height
|
||||||
|
|
||||||
|
Image {
|
||||||
|
id: bg
|
||||||
|
x: -32
|
||||||
|
height: 69
|
||||||
|
source: SkinBank.LOBBY_IMG_DIR + "profile"
|
||||||
|
fillMode: Image.PreserveAspectFit
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Item { Layout.preferredWidth: 16 }
|
||||||
|
|
||||||
|
Image {
|
||||||
|
Layout.preferredWidth: 64
|
||||||
|
Layout.preferredHeight: 64
|
||||||
|
source: SkinBank.getGeneralPicture(Self.avatar)
|
||||||
|
sourceSize.width: 250
|
||||||
|
sourceSize.height: 292
|
||||||
|
sourceClipRect: Qt.rect(61, 0, 128, 128)
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
color: "transparent"
|
||||||
|
border.width: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item { Layout.preferredWidth: 8 }
|
||||||
|
|
||||||
|
Text {
|
||||||
|
Layout.alignment: Qt.AlignTop
|
||||||
|
text: Self.screenName
|
||||||
|
font.pixelSize: 22
|
||||||
|
font.family: fontLibian.name
|
||||||
|
color: "#F0DFAF"
|
||||||
|
style: Text.Outline
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TapHandler {
|
||||||
|
onTapped: {
|
||||||
|
lobby_dialog.source = "LobbyElement/EditProfile.qml";
|
||||||
|
lobby_drawer.open();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -28,6 +28,7 @@ ColumnLayout {
|
||||||
id: playerNum
|
id: playerNum
|
||||||
from: 2
|
from: 2
|
||||||
to: 8
|
to: 8
|
||||||
|
value: config.preferedPlayerNum
|
||||||
|
|
||||||
onValueChanged: {
|
onValueChanged: {
|
||||||
config.preferedPlayerNum = value;
|
config.preferedPlayerNum = value;
|
||||||
|
@ -58,6 +59,24 @@ ColumnLayout {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
anchors.rightMargin: 8
|
||||||
|
spacing: 16
|
||||||
|
Text {
|
||||||
|
text: Backend.translate("Select general num")
|
||||||
|
}
|
||||||
|
SpinBox {
|
||||||
|
id: generalNum
|
||||||
|
from: 3
|
||||||
|
to: 8
|
||||||
|
value: config.preferredGeneralNum
|
||||||
|
|
||||||
|
onValueChanged: {
|
||||||
|
config.preferredGeneralNum = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
CheckBox {
|
CheckBox {
|
||||||
id: freeAssignCheck
|
id: freeAssignCheck
|
||||||
checked: Debugging ? true : false
|
checked: Debugging ? true : false
|
||||||
|
@ -78,6 +97,7 @@ ColumnLayout {
|
||||||
enableFreeAssign: freeAssignCheck.checked,
|
enableFreeAssign: freeAssignCheck.checked,
|
||||||
gameMode: config.preferedMode,
|
gameMode: config.preferedMode,
|
||||||
disabledPack: config.disabledPack,
|
disabledPack: config.disabledPack,
|
||||||
|
generalNum: config.preferredGeneralNum,
|
||||||
}])
|
}])
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
73
qml/Pages/ModesOverview.qml
Normal file
73
qml/Pages/ModesOverview.qml
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import QtQuick.Controls
|
||||||
|
|
||||||
|
Item {
|
||||||
|
RowLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
spacing: 10
|
||||||
|
|
||||||
|
ListView {
|
||||||
|
id: listView
|
||||||
|
width: parent.width * 0.2
|
||||||
|
height: parent.height
|
||||||
|
model: ListModel {
|
||||||
|
id: modeList
|
||||||
|
}
|
||||||
|
highlight: Rectangle { color: "lightsteelblue"; radius: 5 }
|
||||||
|
delegate: Item {
|
||||||
|
width: parent.width
|
||||||
|
height: 40
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: name
|
||||||
|
anchors.centerIn: parent
|
||||||
|
}
|
||||||
|
|
||||||
|
TapHandler {
|
||||||
|
onTapped: {
|
||||||
|
listView.currentIndex = index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
color: "#88EEEEEE"
|
||||||
|
Flickable {
|
||||||
|
width: parent.width - 16
|
||||||
|
height: parent.height - 16
|
||||||
|
anchors.centerIn: parent
|
||||||
|
contentHeight: modeDesc.height
|
||||||
|
ScrollBar.vertical: ScrollBar {}
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: modeDesc
|
||||||
|
width: parent.width - 16
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
text: Backend.translate(":" + modeList.get(listView.currentIndex).orig_name)
|
||||||
|
textFormat: Text.MarkdownText
|
||||||
|
font.pixelSize: 16
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
text: qsTr("Quit")
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
onClicked: {
|
||||||
|
mainStack.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
let mode_data = JSON.parse(Backend.callLuaFunction("GetGameModes", []));
|
||||||
|
for (let d of mode_data) {
|
||||||
|
modeList.append(d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -73,7 +73,7 @@ Item {
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
Rectangle {
|
Rectangle {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
color: "#88888888"
|
color: "#88EEEEEE"
|
||||||
}
|
}
|
||||||
ListView {
|
ListView {
|
||||||
id: packageList
|
id: packageList
|
||||||
|
|
|
@ -27,8 +27,8 @@ GraphicsBox {
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: generalArea
|
id: generalArea
|
||||||
width: (generalList.count >= 5 ? Math.ceil(generalList.count / 2) : Math.max(3, generalList.count)) * 97
|
width: (generalList.count > 8 ? Math.ceil(generalList.count / 2) : Math.max(3, generalList.count)) * 97
|
||||||
height: generalList.count >= 5 ? 290 : 150
|
height: generalList.count > 8 ? 290 : 150
|
||||||
z: 1
|
z: 1
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
|
@ -38,8 +38,8 @@ GraphicsBox {
|
||||||
Item {
|
Item {
|
||||||
width: 93
|
width: 93
|
||||||
height: 130
|
height: 130
|
||||||
x: (index % Math.ceil(generalList.count / (generalList.count >= 5 ? 2 : 1))) * 98 + (generalList.count >= 5 && index > generalList.count / 2 && generalList.count % 2 == 1 ? 50 : 0)
|
x: (index % Math.ceil(generalList.count / (generalList.count > 8 ? 2 : 1))) * 98 + (generalList.count > 8 && index > generalList.count / 2 && generalList.count % 2 == 1 ? 50 : 0)
|
||||||
y: generalList.count < 5 ? 0 : (index < generalList.count / 2 ? 0 : 135)
|
y: generalList.count <= 8 ? 0 : (index < generalList.count / 2 ? 0 : 135)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ GraphicsBox {
|
||||||
spacing: 10
|
spacing: 10
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
text: Backend.translate("$Winner").arg(Backend.translate(winner))
|
text: winner !== "" ? Backend.translate("$Winner").arg(Backend.translate(winner)) : Backend.translate("$NoWinner")
|
||||||
color: "#E4D5A0"
|
color: "#E4D5A0"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@ var DELAYED_TRICK_DIR = AppPath + "/image/card/delayedTrick/";
|
||||||
var EQUIP_ICON_DIR = AppPath + "/image/card/equipIcon/";
|
var EQUIP_ICON_DIR = AppPath + "/image/card/equipIcon/";
|
||||||
var PIXANIM_DIR = AppPath + "/image/anim/"
|
var PIXANIM_DIR = AppPath + "/image/anim/"
|
||||||
var TILE_ICON_DIR = AppPath + "/image/button/tileicon/"
|
var TILE_ICON_DIR = AppPath + "/image/button/tileicon/"
|
||||||
|
var LOBBY_IMG_DIR = AppPath + "/image/lobby/";
|
||||||
|
|
||||||
function getGeneralPicture(name) {
|
function getGeneralPicture(name) {
|
||||||
let data = JSON.parse(Backend.callLuaFunction("GetGeneralData", [name]));
|
let data = JSON.parse(Backend.callLuaFunction("GetGeneralData", [name]));
|
||||||
|
|
195
qml/Splash.qml
Normal file
195
qml/Splash.qml
Normal file
|
@ -0,0 +1,195 @@
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: splash
|
||||||
|
color: "#EEEEEE"
|
||||||
|
z: 100
|
||||||
|
|
||||||
|
property bool loading: true
|
||||||
|
property alias animationRunning: animation.running
|
||||||
|
|
||||||
|
signal disappearing
|
||||||
|
signal disappeared
|
||||||
|
|
||||||
|
Grid {
|
||||||
|
id: main
|
||||||
|
anchors.centerIn: parent
|
||||||
|
rows: splash.width >= splash.height ? 1 : 2
|
||||||
|
columns: splash.width >= splash.height ? 2 : 1
|
||||||
|
horizontalItemAlignment: Grid.AlignHCenter
|
||||||
|
verticalItemAlignment: Grid.AlignVCenter
|
||||||
|
spacing: 25
|
||||||
|
|
||||||
|
Image {
|
||||||
|
id: logo
|
||||||
|
source: AppPath + "/image/icon.png"
|
||||||
|
width: 96
|
||||||
|
height: width
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
spacing: 6
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: fktext
|
||||||
|
text: "FreeKill"
|
||||||
|
// color: "#ffffff"
|
||||||
|
font.pixelSize: 40
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
width: parent.width
|
||||||
|
spacing: 8
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: free
|
||||||
|
text: qsTr("Free")
|
||||||
|
// color: "#ffffff"
|
||||||
|
font.pixelSize: 20
|
||||||
|
opacity: 0
|
||||||
|
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: open
|
||||||
|
text: qsTr("Open")
|
||||||
|
// color: "#ffffff"
|
||||||
|
font.pixelSize: 20
|
||||||
|
opacity: 0
|
||||||
|
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: flexible
|
||||||
|
text: qsTr("Flexible")
|
||||||
|
// color: "#ffffff"
|
||||||
|
font.pixelSize: 20
|
||||||
|
opacity: 0
|
||||||
|
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: text
|
||||||
|
text: qsTr("Press Any Key...")
|
||||||
|
// color: "#ffffff"
|
||||||
|
opacity: 0
|
||||||
|
font.pointSize: 15
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
y: (main.y + main.height + parent.height - height) / 2
|
||||||
|
SequentialAnimation on opacity {
|
||||||
|
id: textAni
|
||||||
|
running: false
|
||||||
|
loops: Animation.Infinite
|
||||||
|
NumberAnimation { from: 0; to: 1; duration: 1600; easing.type: Easing.InOutQuad; }
|
||||||
|
NumberAnimation { from: 1; to: 0; duration: 1600; easing.type: Easing.InOutQuad; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SequentialAnimation {
|
||||||
|
id: animation
|
||||||
|
running: true
|
||||||
|
|
||||||
|
PauseAnimation {
|
||||||
|
duration: 400
|
||||||
|
}
|
||||||
|
|
||||||
|
ParallelAnimation {
|
||||||
|
NumberAnimation {
|
||||||
|
target: fktext
|
||||||
|
property: "opacity"
|
||||||
|
duration: 500
|
||||||
|
easing.type: Easing.InOutQuad
|
||||||
|
to: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
NumberAnimation {
|
||||||
|
target: logo
|
||||||
|
property: "opacity"
|
||||||
|
duration: 500
|
||||||
|
easing.type: Easing.InOutQuad
|
||||||
|
to: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NumberAnimation {
|
||||||
|
target: free
|
||||||
|
property: "opacity"
|
||||||
|
duration: 400
|
||||||
|
easing.type: Easing.InOutQuad
|
||||||
|
to: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
NumberAnimation {
|
||||||
|
target: open
|
||||||
|
property: "opacity"
|
||||||
|
duration: 400
|
||||||
|
easing.type: Easing.InOutQuad
|
||||||
|
to: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
NumberAnimation {
|
||||||
|
target: flexible
|
||||||
|
property: "opacity"
|
||||||
|
duration: 400
|
||||||
|
easing.type: Easing.InOutQuad
|
||||||
|
to: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ScriptAction { script: textAni.start(); }
|
||||||
|
|
||||||
|
PropertyAction { target: splash; property: "loading"; value: false }
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Text {
|
||||||
|
text: qsTr("Powered by Mogara")
|
||||||
|
color: "#f39292"
|
||||||
|
font.pixelSize: 20
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.right: parent.right
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
//--------------------Disappear--------------
|
||||||
|
Behavior on opacity {
|
||||||
|
SequentialAnimation {
|
||||||
|
NumberAnimation { duration: 1200; easing.type: Easing.InOutQuad }
|
||||||
|
ScriptAction { script: disappeared() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MouseArea {
|
||||||
|
acceptedButtons: Qt.AllButtons
|
||||||
|
anchors.fill: parent
|
||||||
|
onClicked: {
|
||||||
|
disappear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Keys.onPressed: {
|
||||||
|
disappear();
|
||||||
|
event.accepted = true
|
||||||
|
}
|
||||||
|
|
||||||
|
NumberAnimation {
|
||||||
|
id: logoMover
|
||||||
|
target: logo
|
||||||
|
property: "x"
|
||||||
|
to: -splash.width
|
||||||
|
duration: 1000
|
||||||
|
easing.type: Easing.InOutQuad
|
||||||
|
}
|
||||||
|
|
||||||
|
function disappear() {
|
||||||
|
disappearing();
|
||||||
|
logoMover.start();
|
||||||
|
opacity = 0;
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,11 +19,9 @@ Rectangle {
|
||||||
radius: 16
|
radius: 16
|
||||||
|
|
||||||
opacity: 0
|
opacity: 0
|
||||||
color: "#F2808A87"
|
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: message
|
id: message
|
||||||
color: "white"
|
|
||||||
horizontalAlignment: Text.AlignHCenter
|
horizontalAlignment: Text.AlignHCenter
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
}
|
}
|
||||||
|
|
15
qml/main.qml
15
qml/main.qml
|
@ -49,11 +49,13 @@ Item {
|
||||||
Component { id: lobby; Lobby {} }
|
Component { id: lobby; Lobby {} }
|
||||||
Component { id: generalsOverview; GeneralsOverview {} }
|
Component { id: generalsOverview; GeneralsOverview {} }
|
||||||
Component { id: cardsOverview; CardsOverview {} }
|
Component { id: cardsOverview; CardsOverview {} }
|
||||||
|
Component { id: modesOverview; ModesOverview {} }
|
||||||
Component { id: room; Room {} }
|
Component { id: room; Room {} }
|
||||||
Component { id: aboutPage; About {} }
|
Component { id: aboutPage; About {} }
|
||||||
|
|
||||||
property var generalsOverviewPage
|
property var generalsOverviewPage
|
||||||
property var cardsOverviewPage
|
property var cardsOverviewPage
|
||||||
|
property alias modesOverviewPage: modesOverview
|
||||||
property alias aboutPage: aboutPage
|
property alias aboutPage: aboutPage
|
||||||
property bool busy: false
|
property bool busy: false
|
||||||
property string busyText: ""
|
property string busyText: ""
|
||||||
|
@ -71,7 +73,7 @@ Item {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
Rectangle {
|
Rectangle {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
color: "#88888888"
|
color: "#88EEEEEE"
|
||||||
}
|
}
|
||||||
Text {
|
Text {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
|
@ -198,9 +200,20 @@ Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
id: splashLoader
|
||||||
|
anchors.fill: parent
|
||||||
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
if (OS !== "Web") {
|
if (OS !== "Web") {
|
||||||
mainStack.push(init);
|
mainStack.push(init);
|
||||||
|
if (!Debugging) {
|
||||||
|
splashLoader.source = "Splash.qml";
|
||||||
|
splashLoader.item.disappeared.connect(() => {
|
||||||
|
splashLoader.source = "";
|
||||||
|
});
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
mainStack.push(webinit);
|
mainStack.push(webinit);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
#include "client.h"
|
||||||
#ifndef Q_OS_WASM
|
#ifndef Q_OS_WASM
|
||||||
#include "server.h"
|
#include "server.h"
|
||||||
#include "packman.h"
|
#include "packman.h"
|
||||||
|
@ -219,6 +220,7 @@ int main(int argc, char *argv[])
|
||||||
Pacman = new PackMan;
|
Pacman = new PackMan;
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
|
engine->rootContext()->setContextProperty("FkVersion", FK_VERSION);
|
||||||
engine->rootContext()->setContextProperty("Backend", &backend);
|
engine->rootContext()->setContextProperty("Backend", &backend);
|
||||||
engine->rootContext()->setContextProperty("Pacman", Pacman);
|
engine->rootContext()->setContextProperty("Pacman", Pacman);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user