Page Menu
Home
Phabricator (Chris)
Search
Configure Global Search
Log In
Files
F119006
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
127 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/data/locale/zh_CN.po b/data/locale/zh_CN.po
index c1914ac..52214c8 100644
--- a/data/locale/zh_CN.po
+++ b/data/locale/zh_CN.po
@@ -1,1191 +1,1295 @@
# Simplified Chinese translation for Me and My Shadow
# Copyright (C) 2012 Me and My Shadow
# This file is distributed under the same license (GNU GPLv3) as the meandmyshadow package.
# acme_pjz <acme_pjz@hotmail.com>, 2012
#
msgid ""
msgstr ""
"Project-Id-Version: Me and my shadow\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2012-07-31 15:41+0800\n"
-"PO-Revision-Date: 2012-07-31 15:42+0800\n"
+"POT-Creation-Date: 2012-07-31 22:23+0800\n"
+"PO-Revision-Date: 2012-07-31 22:30+0800\n"
"Last-Translator: acme_pjz <acme_pjz@hotmail.com>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: \n"
"X-Poedit-Language: Chinese\n"
"X-Poedit-Country: CHINA\n"
"X-Poedit-SourceCharset: utf-8\n"
"X-Poedit-Basepath: .\n"
"X-Poedit-KeywordsList: _;__\n"
"X-Poedit-SearchPath-0: F:\\Projects\\meandmyshadow\\src\n"
#: F:\Projects\meandmyshadow\src/Addons.cpp:40
msgid "Addons"
msgstr "附加组件"
#: F:\Projects\meandmyshadow\src/Addons.cpp:58
msgid "Unable to initialize addon menu:"
msgstr "不能初始化附加组件菜单:"
#: F:\Projects\meandmyshadow\src/Addons.cpp:66
#: F:\Projects\meandmyshadow\src/Addons.cpp:115
msgid "Back"
msgstr "后退"
#: F:\Projects\meandmyshadow\src/Addons.cpp:97
msgid "Levels"
msgstr "关卡列表"
#: F:\Projects\meandmyshadow\src/Addons.cpp:98
msgid "Level Packs"
msgstr "关卡包"
#: F:\Projects\meandmyshadow\src/Addons.cpp:99
msgid "Themes"
msgstr "主题"
#: F:\Projects\meandmyshadow\src/Addons.cpp:119
#: F:\Projects\meandmyshadow\src/Addons.cpp:600
msgid "Install"
msgstr "安装"
#: F:\Projects\meandmyshadow\src/Addons.cpp:123
msgid "Update"
msgstr "升级"
#: F:\Projects\meandmyshadow\src/Addons.cpp:134
msgid "ERROR: unable to download addons file!"
msgstr "错误:无法下载附加组件!"
#: F:\Projects\meandmyshadow\src/Addons.cpp:146
msgid "ERROR: unable to load addon_list file!"
msgstr "错误:无法加载文件addon_list!"
#: F:\Projects\meandmyshadow\src/Addons.cpp:157
msgid "ERROR: Invalid file format of addons file!"
msgstr "错误:文件addons的格式无效!"
#: F:\Projects\meandmyshadow\src/Addons.cpp:178
msgid "ERROR: Unable to create the installed_addons file."
msgstr "错误:无法创建文件installed_addons。"
#: F:\Projects\meandmyshadow\src/Addons.cpp:190
msgid "ERROR: Invalid file format of the installed_addons!"
msgstr "错误:文件installed_addons的格式无效!"
#: F:\Projects\meandmyshadow\src/Addons.cpp:405
#: F:\Projects\meandmyshadow\src/Addons.cpp:422
#: F:\Projects\meandmyshadow\src/Addons.cpp:439
#: F:\Projects\meandmyshadow\src/Addons.cpp:466
#: F:\Projects\meandmyshadow\src/Addons.cpp:483
#: F:\Projects\meandmyshadow\src/Addons.cpp:497
msgid "ERROR: Unable to download addon!"
msgstr "错误:无法下载附加组件"
#: F:\Projects\meandmyshadow\src/Addons.cpp:405
#: F:\Projects\meandmyshadow\src/Addons.cpp:422
#: F:\Projects\meandmyshadow\src/Addons.cpp:439
#: F:\Projects\meandmyshadow\src/Addons.cpp:466
#: F:\Projects\meandmyshadow\src/Addons.cpp:483
#: F:\Projects\meandmyshadow\src/Addons.cpp:497
msgid "ERROR:"
msgstr "错误:"
#: F:\Projects\meandmyshadow\src/Addons.cpp:595
msgid "Uninstall"
msgstr "卸载"
#: F:\Projects\meandmyshadow\src/Block.cpp:547
msgid "On"
msgstr "开启"
#: F:\Projects\meandmyshadow\src/Block.cpp:548
msgid "Off"
msgstr "关闭"
#: F:\Projects\meandmyshadow\src/Functions.cpp:599
#: F:\Projects\meandmyshadow\src/Functions.cpp:600
#: F:\Projects\meandmyshadow\src/Functions.cpp:601
#: F:\Projects\meandmyshadow\src/Functions.cpp:617
msgid "knewave"
msgstr "DroidSansFallback"
#: F:\Projects\meandmyshadow\src/Functions.cpp:605
msgid "Blokletters-Viltstift"
msgstr "DroidSansFallback"
#: F:\Projects\meandmyshadow\src/Functions.cpp:678
msgid "Loading..."
msgstr "正在读取..."
-#: F:\Projects\meandmyshadow\src/Functions.cpp:1209
-#: F:\Projects\meandmyshadow\src/Functions.cpp:1236
-#: F:\Projects\meandmyshadow\src/Functions.cpp:1574
+#: F:\Projects\meandmyshadow\src/Functions.cpp:1210
+#: F:\Projects\meandmyshadow\src/Functions.cpp:1237
+#: F:\Projects\meandmyshadow\src/Functions.cpp:1575
#: F:\Projects\meandmyshadow\src/InputManager.cpp:233
msgid "OK"
msgstr "确定"
-#: F:\Projects\meandmyshadow\src/Functions.cpp:1210
-#: F:\Projects\meandmyshadow\src/Functions.cpp:1222
-#: F:\Projects\meandmyshadow\src/Functions.cpp:1232
-#: F:\Projects\meandmyshadow\src/Functions.cpp:1578
+#: F:\Projects\meandmyshadow\src/Functions.cpp:1211
+#: F:\Projects\meandmyshadow\src/Functions.cpp:1223
+#: F:\Projects\meandmyshadow\src/Functions.cpp:1233
+#: F:\Projects\meandmyshadow\src/Functions.cpp:1579
msgid "Cancel"
msgstr "取消"
-#: F:\Projects\meandmyshadow\src/Functions.cpp:1214
+#: F:\Projects\meandmyshadow\src/Functions.cpp:1215
msgid "Abort"
msgstr "终止"
-#: F:\Projects\meandmyshadow\src/Functions.cpp:1215
-#: F:\Projects\meandmyshadow\src/Functions.cpp:1231
+#: F:\Projects\meandmyshadow\src/Functions.cpp:1216
+#: F:\Projects\meandmyshadow\src/Functions.cpp:1232
msgid "Retry"
msgstr "重试"
-#: F:\Projects\meandmyshadow\src/Functions.cpp:1216
+#: F:\Projects\meandmyshadow\src/Functions.cpp:1217
msgid "Ignore"
msgstr "忽略"
-#: F:\Projects\meandmyshadow\src/Functions.cpp:1220
-#: F:\Projects\meandmyshadow\src/Functions.cpp:1226
+#: F:\Projects\meandmyshadow\src/Functions.cpp:1221
+#: F:\Projects\meandmyshadow\src/Functions.cpp:1227
msgid "Yes"
msgstr "是"
-#: F:\Projects\meandmyshadow\src/Functions.cpp:1221
-#: F:\Projects\meandmyshadow\src/Functions.cpp:1227
+#: F:\Projects\meandmyshadow\src/Functions.cpp:1222
+#: F:\Projects\meandmyshadow\src/Functions.cpp:1228
msgid "No"
msgstr "否"
-#: F:\Projects\meandmyshadow\src/Functions.cpp:1345
+#: F:\Projects\meandmyshadow\src/Functions.cpp:1346
#, c-format
msgid ""
"%s already exists.\n"
"Do you want to overwrite it?"
msgstr ""
"%s 已经存在。\n"
"你是否想要覆盖它?"
-#: F:\Projects\meandmyshadow\src/Functions.cpp:1345
+#: F:\Projects\meandmyshadow\src/Functions.cpp:1346
msgid "Overwrite Prompt"
msgstr "文件覆盖提示"
-#: F:\Projects\meandmyshadow\src/Functions.cpp:1366
-#: F:\Projects\meandmyshadow\src/Functions.cpp:1384
+#: F:\Projects\meandmyshadow\src/Functions.cpp:1367
+#: F:\Projects\meandmyshadow\src/Functions.cpp:1385
#, c-format
msgid "Can't open file %s."
msgstr "不能打开文件 %s。"
-#: F:\Projects\meandmyshadow\src/Functions.cpp:1366
-#: F:\Projects\meandmyshadow\src/Functions.cpp:1384
+#: F:\Projects\meandmyshadow\src/Functions.cpp:1367
+#: F:\Projects\meandmyshadow\src/Functions.cpp:1385
msgid "Error"
msgstr "错误"
-#: F:\Projects\meandmyshadow\src/Functions.cpp:1515
+#: F:\Projects\meandmyshadow\src/Functions.cpp:1516
msgid "Save File"
msgstr "保存文件"
-#: F:\Projects\meandmyshadow\src/Functions.cpp:1515
+#: F:\Projects\meandmyshadow\src/Functions.cpp:1516
msgid "Load File"
msgstr "打开文件"
-#: F:\Projects\meandmyshadow\src/Functions.cpp:1519
+#: F:\Projects\meandmyshadow\src/Functions.cpp:1520
msgid "Search In"
msgstr "查找范围"
-#: F:\Projects\meandmyshadow\src/Functions.cpp:1529
+#: F:\Projects\meandmyshadow\src/Functions.cpp:1530
msgid "File Name"
msgstr "文件名"
-#: F:\Projects\meandmyshadow\src/Game.cpp:245
-#: F:\Projects\meandmyshadow\src/Game.cpp:851
+#: F:\Projects\meandmyshadow\src/Game.cpp:246
+#: F:\Projects\meandmyshadow\src/Game.cpp:917
#, c-format
msgid "Level %d %s"
msgstr "第 %d 关 %s"
-#: F:\Projects\meandmyshadow\src/Game.cpp:669
+#: F:\Projects\meandmyshadow\src/Game.cpp:735
#, c-format
msgid "Press %s key to save the game."
msgstr "按 %s 键来保存游戏。"
-#: F:\Projects\meandmyshadow\src/Game.cpp:674
+#: F:\Projects\meandmyshadow\src/Game.cpp:740
#, c-format
msgid "Press %s key to swap the position of player and shadow."
msgstr "按 %s 键交换你和阴影的位置。"
-#: F:\Projects\meandmyshadow\src/Game.cpp:679
+#: F:\Projects\meandmyshadow\src/Game.cpp:745
#, c-format
msgid "Press %s key to activate the switch."
msgstr "按 %s 键来激活开关。"
-#: F:\Projects\meandmyshadow\src/Game.cpp:684
+#: F:\Projects\meandmyshadow\src/Game.cpp:750
#, c-format
msgid "Press %s key to teleport."
msgstr "按 %s 键传送。"
-#: F:\Projects\meandmyshadow\src/Game.cpp:725
+#: F:\Projects\meandmyshadow\src/Game.cpp:791
#, c-format
msgid "Press %s to restart current level or press %s to load the game."
msgstr "按 %s 键重新开始游戏,或者按 %s 键读取进度。"
-#: F:\Projects\meandmyshadow\src/Game.cpp:737
+#: F:\Projects\meandmyshadow\src/Game.cpp:803
#, c-format
msgid "Press %s to restart current level."
msgstr "按 %s 键重新开始游戏。"
-#: F:\Projects\meandmyshadow\src/Game.cpp:751
+#: F:\Projects\meandmyshadow\src/Game.cpp:817
msgid "Your shadow has died."
msgstr "你的阴影死掉了。"
-#: F:\Projects\meandmyshadow\src/Game.cpp:803
+#: F:\Projects\meandmyshadow\src/Game.cpp:869
#, c-format
msgid "%d recordings"
msgstr "记录数 %d"
-#: F:\Projects\meandmyshadow\src/Game.cpp:843
+#: F:\Projects\meandmyshadow\src/Game.cpp:909
msgid "You've finished:"
msgstr "恭喜你完成了:"
-#: F:\Projects\meandmyshadow\src/Game.cpp:1028
+#: F:\Projects\meandmyshadow\src/Game.cpp:1094
#, c-format
msgid "Time: %-.2fs"
msgstr "时间: %-.2f秒"
-#: F:\Projects\meandmyshadow\src/Game.cpp:1037
+#: F:\Projects\meandmyshadow\src/Game.cpp:1103
#, c-format
msgid "Best time: %-.2fs"
msgstr "最佳时间: %-.2f秒"
-#: F:\Projects\meandmyshadow\src/Game.cpp:1048
+#: F:\Projects\meandmyshadow\src/Game.cpp:1114
#, c-format
msgid "Target time: %-.2fs"
msgstr "目标时间: %-.2f秒"
-#: F:\Projects\meandmyshadow\src/Game.cpp:1069
+#: F:\Projects\meandmyshadow\src/Game.cpp:1135
#, c-format
msgid "Recordings: %d"
msgstr "记录次数: %d"
-#: F:\Projects\meandmyshadow\src/Game.cpp:1077
+#: F:\Projects\meandmyshadow\src/Game.cpp:1143
#, c-format
msgid "Best recordings: %d"
msgstr "最佳记录次数: %d"
-#: F:\Projects\meandmyshadow\src/Game.cpp:1087
+#: F:\Projects\meandmyshadow\src/Game.cpp:1153
#, c-format
msgid "Target recordings: %d"
msgstr "目标记录次数: %d"
-#: F:\Projects\meandmyshadow\src/Game.cpp:1100
+#: F:\Projects\meandmyshadow\src/Game.cpp:1166
#, c-format
msgid "You earned the %s medal"
msgstr "你拿到了%s"
-#: F:\Projects\meandmyshadow\src/Game.cpp:1100
+#: F:\Projects\meandmyshadow\src/Game.cpp:1166
msgid "GOLD"
msgstr "金牌"
-#: F:\Projects\meandmyshadow\src/Game.cpp:1100
+#: F:\Projects\meandmyshadow\src/Game.cpp:1166
msgid "SILVER"
msgstr "银牌"
-#: F:\Projects\meandmyshadow\src/Game.cpp:1100
+#: F:\Projects\meandmyshadow\src/Game.cpp:1166
msgid "BRONZE"
msgstr "铜牌"
-#: F:\Projects\meandmyshadow\src/Game.cpp:1115
+#: F:\Projects\meandmyshadow\src/Game.cpp:1181
msgid "Menu"
msgstr "菜单"
-#: F:\Projects\meandmyshadow\src/Game.cpp:1122
+#: F:\Projects\meandmyshadow\src/Game.cpp:1188
#: F:\Projects\meandmyshadow\src/InputManager.cpp:44
msgid "Restart"
msgstr "重新开始"
-#: F:\Projects\meandmyshadow\src/Game.cpp:1129
+#: F:\Projects\meandmyshadow\src/Game.cpp:1195
msgid "Next"
msgstr "下一关"
-#: F:\Projects\meandmyshadow\src/Game.cpp:1184
+#: F:\Projects\meandmyshadow\src/Game.cpp:1250
msgid "Game replay is done."
msgstr "游戏重放已经完成。"
-#: F:\Projects\meandmyshadow\src/Game.cpp:1184
+#: F:\Projects\meandmyshadow\src/Game.cpp:1250
msgid "Game Replay"
msgstr "游戏重放"
-#: F:\Projects\meandmyshadow\src/Game.cpp:1355
-#: F:\Projects\meandmyshadow\src/Game.cpp:1357
+#: F:\Projects\meandmyshadow\src/Game.cpp:1421
+#: F:\Projects\meandmyshadow\src/Game.cpp:1423
msgid "Congratulations"
msgstr "恭喜你"
-#: F:\Projects\meandmyshadow\src/Game.cpp:1357
+#: F:\Projects\meandmyshadow\src/Game.cpp:1423
msgid "You have finished the levelpack!"
msgstr "你已经完成了整个关卡包!"
#: F:\Projects\meandmyshadow\src/InputManager.cpp:43
msgid "Up (in menu)"
msgstr "上(在菜单中)"
#: F:\Projects\meandmyshadow\src/InputManager.cpp:43
msgid "Down (in menu)"
msgstr "下(在菜单中)"
#: F:\Projects\meandmyshadow\src/InputManager.cpp:43
msgid "Left"
msgstr "左"
#: F:\Projects\meandmyshadow\src/InputManager.cpp:43
msgid "Right"
msgstr "右"
#: F:\Projects\meandmyshadow\src/InputManager.cpp:43
msgid "Jump"
msgstr "跳跃"
#: F:\Projects\meandmyshadow\src/InputManager.cpp:43
msgid "Action"
msgstr "动作键"
#: F:\Projects\meandmyshadow\src/InputManager.cpp:43
msgid "Space (Record)"
msgstr "空格(记录键)"
#: F:\Projects\meandmyshadow\src/InputManager.cpp:43
msgid "Cancel recording"
msgstr "取消记录"
#: F:\Projects\meandmyshadow\src/InputManager.cpp:44
msgid "Escape"
msgstr "退出"
#: F:\Projects\meandmyshadow\src/InputManager.cpp:44
msgid "Tab (View shadow/Level prop.)"
msgstr "Tab (切换视角/关卡属性)"
#: F:\Projects\meandmyshadow\src/InputManager.cpp:44
msgid "Save game (in editor)"
msgstr "保存游戏(在地图编辑器中)"
#: F:\Projects\meandmyshadow\src/InputManager.cpp:44
msgid "Load game"
msgstr "读取游戏"
#: F:\Projects\meandmyshadow\src/InputManager.cpp:44
msgid "Swap (in editor)"
msgstr "交换玩家和阴影的位置(在地图编辑器中)"
#: F:\Projects\meandmyshadow\src/InputManager.cpp:45
msgid "Teleport (in editor)"
msgstr "传送(在地图编辑器中)"
#: F:\Projects\meandmyshadow\src/InputManager.cpp:45
msgid "Suicide (in editor)"
msgstr "自杀(在地图编辑器中)"
#: F:\Projects\meandmyshadow\src/InputManager.cpp:45
msgid "Shift (in editor)"
msgstr "Shift (地图编辑器辅助按键)"
#: F:\Projects\meandmyshadow\src/InputManager.cpp:45
msgid "Next block type (in Editor)"
msgstr "下一个砖块类型(在地图编辑器中)"
#: F:\Projects\meandmyshadow\src/InputManager.cpp:46
msgid "Previous block type (in editor)"
msgstr "上一个砖块类型(在地图编辑器中)"
#: F:\Projects\meandmyshadow\src/InputManager.cpp:46
msgid "Select (in menu)"
msgstr "选择键(在菜单中)"
#: F:\Projects\meandmyshadow\src/InputManager.cpp:204
msgid "Config Keys"
msgstr "设置按键"
#: F:\Projects\meandmyshadow\src/InputManager.cpp:207
msgid "Select an item and press a key to config it."
msgstr "选择一个项目,然后按键进行设置。"
#: F:\Projects\meandmyshadow\src/InputManager.cpp:221
msgid "Primary key"
msgstr "主按键"
#: F:\Projects\meandmyshadow\src/InputManager.cpp:222
msgid "Alternative key"
msgstr "辅助按键"
#: F:\Projects\meandmyshadow\src/InputManager.cpp:228
msgid "Unset the key"
msgstr "取消设置"
#: F:\Projects\meandmyshadow\src/InputManager.cpp:298
msgid "(Not set)"
msgstr "(未设置)"
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:62
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:63
msgid "Block"
msgstr "砖块"
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:62
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:63
msgid "Player Start"
msgstr "玩家起点"
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:62
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:63
msgid "Shadow Start"
msgstr "阴影起点"
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:63
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:64
msgid "Exit"
msgstr "终点"
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:63
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:64
msgid "Shadow Block"
msgstr "阴影砖块"
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:63
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:64
msgid "Spikes"
msgstr "带刺砖块"
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:64
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:65
msgid "Checkpoint"
msgstr "记录点"
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:64
-#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:290
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:65
+#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:291
msgid "Swap"
msgstr "交换点"
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:64
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2461
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:65
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2468
msgid "Fragile"
msgstr "易碎砖块"
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:65
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:66
msgid "Moving Block"
msgstr "移动砖块"
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:65
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:66
msgid "Moving Shadow Block"
msgstr "移动阴影砖块"
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:65
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:66
msgid "Moving Spikes"
msgstr "移动的刺"
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:66
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:67
msgid "Teleporter"
msgstr "传送点"
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:66
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2380
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:67
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2387
msgid "Button"
msgstr "按钮"
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:66
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2382
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:67
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2389
msgid "Switch"
msgstr "开关"
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:67
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:68
msgid "Conveyor Belt"
msgstr "传送带"
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:67
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:68
msgid "Shadow Conveyor Belt"
msgstr "阴影传送带"
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:67
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:68
msgid "Notification Block"
msgstr "消息方块"
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:67
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:68
msgid "Collectable"
msgstr "可收集的物品"
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:153
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:154
msgid "Toolbox"
msgstr "工具箱"
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:505
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:3117
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:506
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:3124
msgid "Select"
msgstr "选择"
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:520
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:3126
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:521
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:3133
msgid "Configure"
msgstr "设置"
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:535
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:536
msgid "Link"
msgstr "链接"
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:550
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:3123
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:551
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:3130
msgid "Delete"
msgstr "删除"
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:939
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:946
msgid "Are you sure you want to quit?"
msgstr "你确定要退出吗?"
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:939
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:946
msgid "Quit prompt"
msgstr "退出提示"
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1038
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1040
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1498
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1500
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1045
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1047
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1505
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1507
#, c-format
msgid "Level \"%s\" saved"
msgstr "关卡“%s”已保存"
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1038
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1040
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1498
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1500
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1045
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1047
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1505
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1507
msgid "Saved"
msgstr "已保存"
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1513
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:3132
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1520
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:3139
msgid "Level settings"
msgstr "关卡设置"
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1517
-#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:202
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1524
+#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:203
msgid "Name:"
msgstr "名称:"
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1523
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1530
msgid "Theme:"
msgstr "主题:"
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1538
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1545
msgid "Target time (s):"
msgstr "目标时间(秒):"
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1549
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1556
msgid "Target recordings:"
msgstr "目标记录数:"
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2110
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2300
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2117
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2307
msgid "Defined"
msgstr "已设置"
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2113
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2303
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2374
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2120
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2310
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2381
msgid "None"
msgstr "无"
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2120
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2127
msgid "Moving block"
msgstr "移动砖块"
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2123
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2130
msgid "Moving shadow block"
msgstr "移动阴影砖块"
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2126
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2133
msgid "Moving spikes"
msgstr "移动的刺"
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2133
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2252
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2140
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2259
msgid "Enabled"
msgstr "启用"
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2139
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2146
msgid "Loop"
msgstr "循环"
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2145
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2152
msgid "Path"
msgstr "路径"
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2196
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2203
msgid "Notification block"
msgstr "消息方块"
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2199
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2206
msgid "Enter message here:"
msgstr "输入消息:"
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2244
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2251
msgid "Shadow Conveyor belt"
msgstr "阴影传送带"
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2246
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2253
msgid "Conveyor belt"
msgstr "传送带"
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2258
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2265
msgid "Enter speed here:"
msgstr "输入速度:"
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2307
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2314
msgid "Portal"
msgstr "传送门"
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2310
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2317
msgid "Activate on touch"
msgstr "接触时传送"
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2316
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2410
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2323
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2417
msgid "Targets:"
msgstr "目标:"
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2371
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2378
#, c-format
msgid "%d Defined"
msgstr "已设置 %d 个"
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2387
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2394
msgid "Behaviour:"
msgstr "行为:"
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2395
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2402
msgid "Toggle"
msgstr "切换"
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2464
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2471
msgid "State:"
msgstr "状态:"
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2470
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2477
msgid "Complete"
msgstr "完整的"
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2471
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2478
msgid "One step"
msgstr "踩了一次"
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2472
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2479
msgid "Two steps"
msgstr "踩了两次"
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2473
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2480
msgid "Gone"
msgstr "已经破碎"
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:3120
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:3127
msgid "Add"
msgstr "添加"
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:3129
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:3136
#: F:\Projects\meandmyshadow\src/LevelPlaySelect.cpp:66
msgid "Play"
msgstr "开始游戏"
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:3135
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:3142
msgid "Save level"
msgstr "保存关卡"
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:3138
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:3145
msgid "Back to menu"
msgstr "回主菜单"
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:3187
-#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:3193
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:3194
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:3200
#, c-format
msgid "Movespeed: %s"
msgstr "移动速度: %s"
-#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:43
+#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:44
msgid "Map Editor"
msgstr "地图编辑器"
-#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:80
+#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:81
msgid "New Levelpack"
msgstr "新建关卡包"
-#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:85
+#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:86
msgid "Pack Properties"
msgstr "关卡包属性"
-#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:90
+#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:91
msgid "Remove Pack"
msgstr "删除关卡包"
-#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:95
+#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:96
msgid "Move Map"
msgstr "移动地图"
-#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:103
+#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:104
msgid "Remove Map"
msgstr "删除地图"
-#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:108
+#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:109
msgid "Edit Map"
msgstr "编辑地图"
-#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:199
+#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:200
msgid "Properties"
msgstr "属性"
-#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:211
+#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:212
msgid "Description:"
msgstr "描述:"
-#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:220
+#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:221
msgid "Congratulation text:"
msgstr "完成提示:"
-#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:248
-#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:401
+#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:249
+#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:402
msgid "Add level"
msgstr "增加关卡"
-#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:251
+#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:252
msgid "File name:"
msgstr "文件名:"
-#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:275
+#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:276
msgid "Move level"
msgstr "移动关卡"
-#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:278
+#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:279
msgid "Level: "
msgstr "关卡:"
-#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:288
+#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:289
msgid "Before"
msgstr "之前"
-#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:289
+#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:290
msgid "After"
msgstr "之后"
-#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:464
+#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:465
msgid "Are you sure?"
msgstr "你确定吗?"
-#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:464
+#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:465
msgid "Remove prompt"
msgstr "删除提示"
-#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:609
+#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:610
msgid "No file name given for the new level."
msgstr "没有给新关卡指定文件名。"
-#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:609
+#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:610
msgid "Missing file name"
msgstr "文件名未指定"
-#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:686
+#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:691
msgid "The entered level number isn't valid!"
msgstr "输入的关卡编号无效!"
-#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:686
+#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:691
msgid "Illegal number"
msgstr "无效编号"
#: F:\Projects\meandmyshadow\src/LevelPlaySelect.cpp:44
msgid "Select Level"
msgstr "选择关卡"
#: F:\Projects\meandmyshadow\src/LevelPlaySelect.cpp:93
msgid "Choose a level"
msgstr "选择一个关卡"
#: F:\Projects\meandmyshadow\src/LevelPlaySelect.cpp:94
msgid "Time:"
msgstr "时间:"
#: F:\Projects\meandmyshadow\src/LevelPlaySelect.cpp:95
-#: F:\Projects\meandmyshadow\src/StatisticsScreen.cpp:168
+#: F:\Projects\meandmyshadow\src/StatisticsScreen.cpp:171
msgid "Recordings:"
msgstr "记录次数:"
-#: F:\Projects\meandmyshadow\src/StatisticsManager.cpp:57
+#: F:\Projects\meandmyshadow\src/StatisticsManager.cpp:59
msgid "Newbie"
msgstr "新手"
-#: F:\Projects\meandmyshadow\src/StatisticsManager.cpp:57
+#: F:\Projects\meandmyshadow\src/StatisticsManager.cpp:59
msgid "Congratulations, you completed one level!"
msgstr "恭喜你成功完成了一个关卡!"
-#: F:\Projects\meandmyshadow\src/StatisticsManager.cpp:58
+#: F:\Projects\meandmyshadow\src/StatisticsManager.cpp:60
msgid "Experienced player"
msgstr "有经验的玩家"
-#: F:\Projects\meandmyshadow\src/StatisticsManager.cpp:58
+#: F:\Projects\meandmyshadow\src/StatisticsManager.cpp:60
msgid "Completed 50 levels."
msgstr "完成50个关卡。"
-#: F:\Projects\meandmyshadow\src/StatisticsManager.cpp:59
+#: F:\Projects\meandmyshadow\src/StatisticsManager.cpp:61
+msgid "Good job!"
+msgstr "干得好!"
+
+#: F:\Projects\meandmyshadow\src/StatisticsManager.cpp:61
+msgid "Get your first gold medal."
+msgstr "拿到你的第一个金牌。"
+
+#: F:\Projects\meandmyshadow\src/StatisticsManager.cpp:62
msgid "Expert"
msgstr "专家"
-#: F:\Projects\meandmyshadow\src/StatisticsManager.cpp:59
+#: F:\Projects\meandmyshadow\src/StatisticsManager.cpp:62
msgid "Earned 50 gold medal."
-msgstr "拿到50个金牌"
+msgstr "拿到50个金牌。"
-#: F:\Projects\meandmyshadow\src/StatisticsManager.cpp:60
+#: F:\Projects\meandmyshadow\src/StatisticsManager.cpp:64
msgid "Graduate"
msgstr "毕业生"
-#: F:\Projects\meandmyshadow\src/StatisticsManager.cpp:60
+#: F:\Projects\meandmyshadow\src/StatisticsManager.cpp:64
msgid "Complete the tutorial level pack."
msgstr "完成教程关卡包。"
-#: F:\Projects\meandmyshadow\src/StatisticsManager.cpp:61
+#: F:\Projects\meandmyshadow\src/StatisticsManager.cpp:65
msgid "Outstanding graduate"
msgstr "优秀毕业生"
-#: F:\Projects\meandmyshadow\src/StatisticsManager.cpp:61
+#: F:\Projects\meandmyshadow\src/StatisticsManager.cpp:65
msgid "Complete the tutorial level pack with all levels gold medal."
msgstr "以全部金牌的成绩完成教学关卡包。"
-#: F:\Projects\meandmyshadow\src/StatisticsManager.cpp:276
+#: F:\Projects\meandmyshadow\src/StatisticsManager.cpp:67
+msgid "Addicted"
+msgstr "入迷"
+
+#: F:\Projects\meandmyshadow\src/StatisticsManager.cpp:67
+msgid "Played Me and My Shadow for more than 2 hours."
+msgstr "玩Me and My Shadow超过2小时。"
+
+#: F:\Projects\meandmyshadow\src/StatisticsManager.cpp:68
+msgid "Me and My Shadow loyal fan"
+msgstr "Me and My Shadow忠实粉丝"
+
+#: F:\Projects\meandmyshadow\src/StatisticsManager.cpp:68
+msgid "Played Me and My Shadow for more than 24 hours."
+msgstr "玩Me and My Shadow超过24小时。"
+
+#: F:\Projects\meandmyshadow\src/StatisticsManager.cpp:70
+msgid "Constructor"
+msgstr "建造师"
+
+#: F:\Projects\meandmyshadow\src/StatisticsManager.cpp:70
+msgid "Use the level editor for more than 2 hours."
+msgstr "使用地图编辑器超过2小时。"
+
+#: F:\Projects\meandmyshadow\src/StatisticsManager.cpp:71
+msgid "The creator"
+msgstr "造物主"
+
+#: F:\Projects\meandmyshadow\src/StatisticsManager.cpp:71
+msgid "Use the level editor for more than 24 hours."
+msgstr "使用地图编辑器超过24小时。"
+
+#: F:\Projects\meandmyshadow\src/StatisticsManager.cpp:73
+msgid "Look, cute level!"
+msgstr "看,可爱的关卡!"
+
+#: F:\Projects\meandmyshadow\src/StatisticsManager.cpp:73
+msgid "Created your first level."
+msgstr "创建你的第一个关卡。"
+
+#: F:\Projects\meandmyshadow\src/StatisticsManager.cpp:74
+msgid "The level museum"
+msgstr "关卡博物馆"
+
+#: F:\Projects\meandmyshadow\src/StatisticsManager.cpp:74
+msgid "Created 50 levels."
+msgstr "创建了50个关卡。"
+
+#: F:\Projects\meandmyshadow\src/StatisticsManager.cpp:76
+msgid "Frog"
+msgstr "青蛙"
+
+#: F:\Projects\meandmyshadow\src/StatisticsManager.cpp:76
+msgid "Jump for 1000 times."
+msgstr "跳跃了1000次。"
+
+#: F:\Projects\meandmyshadow\src/StatisticsManager.cpp:78
+msgid "Be careful!"
+msgstr "小心!"
+
+#: F:\Projects\meandmyshadow\src/StatisticsManager.cpp:78
+msgid "The first death."
+msgstr "第一次挂掉。"
+
+#: F:\Projects\meandmyshadow\src/StatisticsManager.cpp:79
+msgid "It doesn't matter..."
+msgstr "没关系……"
+
+#: F:\Projects\meandmyshadow\src/StatisticsManager.cpp:79
+msgid "Died for 50 times."
+msgstr "挂掉50次。"
+
+#: F:\Projects\meandmyshadow\src/StatisticsManager.cpp:80
+msgid "Expert of trial and error"
+msgstr "试错专家"
+
+#: F:\Projects\meandmyshadow\src/StatisticsManager.cpp:80
+msgid "Died for 1000 times."
+msgstr "挂掉1000次。"
+
+#: F:\Projects\meandmyshadow\src/StatisticsManager.cpp:82
+msgid "Double kill"
+msgstr "双重击杀"
+
+#: F:\Projects\meandmyshadow\src/StatisticsManager.cpp:82
+msgid "Make both player and shadow die."
+msgstr "让玩家和阴影都挂掉。"
+
+#: F:\Projects\meandmyshadow\src/StatisticsManager.cpp:85
+msgid "Programmer"
+msgstr "程序员"
+
+#: F:\Projects\meandmyshadow\src/StatisticsManager.cpp:85
+msgid "Played the development version of Me and My Shadow."
+msgstr "玩过Me and My Shadow的开发版本。"
+
+#: F:\Projects\meandmyshadow\src/StatisticsManager.cpp:318
msgid "New achievement:"
msgstr "新成就:"
-#: F:\Projects\meandmyshadow\src/StatisticsScreen.cpp:126
+#: F:\Projects\meandmyshadow\src/StatisticsScreen.cpp:129
msgid "Achievements and Statistics"
msgstr "成就与统计信息"
-#: F:\Projects\meandmyshadow\src/StatisticsScreen.cpp:150
+#: F:\Projects\meandmyshadow\src/StatisticsScreen.cpp:153
msgid "Total"
msgstr "总计"
-#: F:\Projects\meandmyshadow\src/StatisticsScreen.cpp:159
+#: F:\Projects\meandmyshadow\src/StatisticsScreen.cpp:162
msgid "Traveling distance (m)"
msgstr "旅行距离(米)"
-#: F:\Projects\meandmyshadow\src/StatisticsScreen.cpp:160
+#: F:\Projects\meandmyshadow\src/StatisticsScreen.cpp:163
msgid "Jump times"
msgstr "跳跃次数"
-#: F:\Projects\meandmyshadow\src/StatisticsScreen.cpp:161
+#: F:\Projects\meandmyshadow\src/StatisticsScreen.cpp:164
msgid "Die times"
msgstr "死亡次数"
-#: F:\Projects\meandmyshadow\src/StatisticsScreen.cpp:168
+#: F:\Projects\meandmyshadow\src/StatisticsScreen.cpp:171
msgid "Switch pulled times:"
msgstr "使用开关次数:"
-#: F:\Projects\meandmyshadow\src/StatisticsScreen.cpp:169
+#: F:\Projects\meandmyshadow\src/StatisticsScreen.cpp:172
msgid "Swap times:"
msgstr "交换次数:"
-#: F:\Projects\meandmyshadow\src/StatisticsScreen.cpp:176
+#: F:\Projects\meandmyshadow\src/StatisticsScreen.cpp:179
msgid "Completed levels:"
msgstr "完成关卡数:"
-#: F:\Projects\meandmyshadow\src/StatisticsScreen.cpp:218
-msgid "Playing time:"
-msgstr "玩游戏用时:"
+#: F:\Projects\meandmyshadow\src/StatisticsScreen.cpp:221
+msgid "In-game time:"
+msgstr "游戏用时:"
-#: F:\Projects\meandmyshadow\src/StatisticsScreen.cpp:231
+#: F:\Projects\meandmyshadow\src/StatisticsScreen.cpp:234
msgid "Level editing time:"
msgstr "地图编辑用时:"
-#: F:\Projects\meandmyshadow\src/StatisticsScreen.cpp:243
+#: F:\Projects\meandmyshadow\src/StatisticsScreen.cpp:246
msgid "Created levels:"
msgstr "创建的关卡:"
-#: F:\Projects\meandmyshadow\src/StatisticsScreen.cpp:289
+#: F:\Projects\meandmyshadow\src/StatisticsScreen.cpp:292
msgid "You don't have any achievements now. Play the game and try to earn some!"
msgstr "你目前没有获得任何成就。试着通过玩游戏获取一些!"
-#: F:\Projects\meandmyshadow\src/StatisticsScreen.cpp:318
+#: F:\Projects\meandmyshadow\src/StatisticsScreen.cpp:321
msgid "Achievements"
msgstr "成就"
-#: F:\Projects\meandmyshadow\src/StatisticsScreen.cpp:319
+#: F:\Projects\meandmyshadow\src/StatisticsScreen.cpp:322
msgid "Statistics"
msgstr "统计信息"
-#: F:\Projects\meandmyshadow\src/TitleMenu.cpp:49
+#: F:\Projects\meandmyshadow\src/TitleMenu.cpp:50
msgid "Options"
msgstr "选项"
-#: F:\Projects\meandmyshadow\src/TitleMenu.cpp:52
+#: F:\Projects\meandmyshadow\src/TitleMenu.cpp:53
msgid "Quit"
msgstr "退出"
-#: F:\Projects\meandmyshadow\src/TitleMenu.cpp:128
+#: F:\Projects\meandmyshadow\src/TitleMenu.cpp:129
msgid "Enable internet in order to install addons."
msgstr "启用网络访问,才能下载附加组件。"
-#: F:\Projects\meandmyshadow\src/TitleMenu.cpp:128
+#: F:\Projects\meandmyshadow\src/TitleMenu.cpp:129
msgid "Internet disabled"
msgstr "网络已禁用"
-#: F:\Projects\meandmyshadow\src/TitleMenu.cpp:205
-#: F:\Projects\meandmyshadow\src/TitleMenu.cpp:707
+#: F:\Projects\meandmyshadow\src/TitleMenu.cpp:206
+#: F:\Projects\meandmyshadow\src/TitleMenu.cpp:710
msgid "Credits"
msgstr "作者"
-#: F:\Projects\meandmyshadow\src/TitleMenu.cpp:236
+#: F:\Projects\meandmyshadow\src/TitleMenu.cpp:237
msgid "Settings"
msgstr "选项"
-#: F:\Projects\meandmyshadow\src/TitleMenu.cpp:280
+#: F:\Projects\meandmyshadow\src/TitleMenu.cpp:281
msgid "Music"
msgstr "音乐"
-#: F:\Projects\meandmyshadow\src/TitleMenu.cpp:288
+#: F:\Projects\meandmyshadow\src/TitleMenu.cpp:289
msgid "Sound"
msgstr "音效"
-#: F:\Projects\meandmyshadow\src/TitleMenu.cpp:296
+#: F:\Projects\meandmyshadow\src/TitleMenu.cpp:297
msgid "Fullscreen"
msgstr "全屏幕"
-#: F:\Projects\meandmyshadow\src/TitleMenu.cpp:301
+#: F:\Projects\meandmyshadow\src/TitleMenu.cpp:302
msgid "Resolution"
msgstr "分辨率"
-#: F:\Projects\meandmyshadow\src/TitleMenu.cpp:383
+#: F:\Projects\meandmyshadow\src/TitleMenu.cpp:384
msgid "Language"
msgstr "语言"
-#: F:\Projects\meandmyshadow\src/TitleMenu.cpp:392
+#: F:\Projects\meandmyshadow\src/TitleMenu.cpp:393
msgid "Auto-Detect"
msgstr "自动检测"
-#: F:\Projects\meandmyshadow\src/TitleMenu.cpp:420
+#: F:\Projects\meandmyshadow\src/TitleMenu.cpp:421
msgid "Theme"
msgstr "主题"
-#: F:\Projects\meandmyshadow\src/TitleMenu.cpp:453
+#: F:\Projects\meandmyshadow\src/TitleMenu.cpp:454
msgid "Level themes"
msgstr "默认主题"
-#: F:\Projects\meandmyshadow\src/TitleMenu.cpp:458
+#: F:\Projects\meandmyshadow\src/TitleMenu.cpp:459
msgid "Internet"
msgstr "网络"
-#: F:\Projects\meandmyshadow\src/TitleMenu.cpp:464
+#: F:\Projects\meandmyshadow\src/TitleMenu.cpp:465
msgid "Internet proxy"
msgstr "网络代理"
-#: F:\Projects\meandmyshadow\src/TitleMenu.cpp:481
+#: F:\Projects\meandmyshadow\src/TitleMenu.cpp:482
msgid "Clear Progress"
msgstr "清除进度"
-#: F:\Projects\meandmyshadow\src/TitleMenu.cpp:500
+#: F:\Projects\meandmyshadow\src/TitleMenu.cpp:501
msgid "Save Changes"
msgstr "保存变更"
-#: F:\Projects\meandmyshadow\src/TitleMenu.cpp:610
+#: F:\Projects\meandmyshadow\src/TitleMenu.cpp:611
msgid "Do you really want to reset level progress?"
msgstr "你确定要清除游戏进度吗?"
-#: F:\Projects\meandmyshadow\src/TitleMenu.cpp:610
+#: F:\Projects\meandmyshadow\src/TitleMenu.cpp:611
msgid "Warning"
msgstr "警告"
# TRANSLATORS: name of a key
#: F:\Projects\meandmyshadow\src/dummy.h:1
msgid "backspace"
msgstr "backspace"
# TRANSLATORS: name of a key
#: F:\Projects\meandmyshadow\src/dummy.h:1
msgid "tab"
msgstr "tab"
# TRANSLATORS: name of a key
#: F:\Projects\meandmyshadow\src/dummy.h:1
msgid "clear"
msgstr "clear"
# TRANSLATORS: name of a key
#: F:\Projects\meandmyshadow\src/dummy.h:1
msgid "return"
msgstr "回车"
# TRANSLATORS: name of a key
#: F:\Projects\meandmyshadow\src/dummy.h:1
msgid "pause"
msgstr "pause"
# TRANSLATORS: name of a key
#: F:\Projects\meandmyshadow\src/dummy.h:1
msgid "escape"
msgstr "escape"
# TRANSLATORS: name of a key
#: F:\Projects\meandmyshadow\src/dummy.h:1
msgid "space"
msgstr "空格"
#: F:\Projects\meandmyshadow\src/dummy.h:1
msgid "delete"
msgstr "delete"
#: F:\Projects\meandmyshadow\src/dummy.h:1
msgid "enter"
msgstr "enter"
# TRANSLATORS: name of a key
#: F:\Projects\meandmyshadow\src/dummy.h:1
msgid "equals"
msgstr "equals"
# TRANSLATORS: name of a key
#: F:\Projects\meandmyshadow\src/dummy.h:2
msgid "up"
msgstr "上"
#: F:\Projects\meandmyshadow\src/dummy.h:2
msgid "down"
msgstr "下"
# TRANSLATORS: name of a key
#: F:\Projects\meandmyshadow\src/dummy.h:2
msgid "right"
msgstr "右"
#: F:\Projects\meandmyshadow\src/dummy.h:2
msgid "left"
msgstr "左"
# TRANSLATORS: name of a key
#: F:\Projects\meandmyshadow\src/dummy.h:2
msgid "insert"
msgstr "insert"
#: F:\Projects\meandmyshadow\src/dummy.h:2
msgid "home"
msgstr "home"
#: F:\Projects\meandmyshadow\src/dummy.h:2
msgid "end"
msgstr "end"
# TRANSLATORS: name of a key
#: F:\Projects\meandmyshadow\src/dummy.h:2
msgid "page up"
msgstr "page up"
# TRANSLATORS: name of a key
#: F:\Projects\meandmyshadow\src/dummy.h:2
msgid "page down"
msgstr "page down"
# TRANSLATORS: name of a key
#: F:\Projects\meandmyshadow\src/dummy.h:2
msgid "numlock"
msgstr "numlock"
# TRANSLATORS: name of a key
#: F:\Projects\meandmyshadow\src/dummy.h:2
msgid "caps lock"
msgstr "caps lock"
# TRANSLATORS: name of a key
#: F:\Projects\meandmyshadow\src/dummy.h:3
msgid "scroll lock"
msgstr "scroll lock"
# TRANSLATORS: name of a key
#: F:\Projects\meandmyshadow\src/dummy.h:3
msgid "right shift"
msgstr "右 shift"
# TRANSLATORS: name of a key
#: F:\Projects\meandmyshadow\src/dummy.h:3
msgid "left shift"
msgstr "左 shift"
# TRANSLATORS: name of a key
#: F:\Projects\meandmyshadow\src/dummy.h:3
msgid "right ctrl"
msgstr "右 ctrl"
# TRANSLATORS: name of a key
#: F:\Projects\meandmyshadow\src/dummy.h:3
msgid "left ctrl"
msgstr "左 ctrl"
# TRANSLATORS: name of a key
#: F:\Projects\meandmyshadow\src/dummy.h:3
msgid "right alt"
msgstr "右 alt"
# TRANSLATORS: name of a key
#: F:\Projects\meandmyshadow\src/dummy.h:3
msgid "left alt"
msgstr "左 alt"
# TRANSLATORS: name of a key
#: F:\Projects\meandmyshadow\src/dummy.h:4
msgid "right meta"
msgstr "右 meta"
# TRANSLATORS: name of a key
#: F:\Projects\meandmyshadow\src/dummy.h:4
msgid "left meta"
msgstr "左 meta"
# TRANSLATORS: name of a key
#: F:\Projects\meandmyshadow\src/dummy.h:4
msgid "left super"
msgstr "左 super"
# TRANSLATORS: name of a key
#: F:\Projects\meandmyshadow\src/dummy.h:4
msgid "right super"
msgstr "右 super"
# TRANSLATORS: name of a key
#: F:\Projects\meandmyshadow\src/dummy.h:4
msgid "alt gr"
msgstr "alt gr"
# TRANSLATORS: name of a key
#: F:\Projects\meandmyshadow\src/dummy.h:4
msgid "compose"
msgstr "compose"
# TRANSLATORS: name of a key
#: F:\Projects\meandmyshadow\src/dummy.h:4
msgid "help"
msgstr "help"
# TRANSLATORS: name of a key
#: F:\Projects\meandmyshadow\src/dummy.h:4
msgid "print screen"
msgstr "print screen"
# TRANSLATORS: name of a key
#: F:\Projects\meandmyshadow\src/dummy.h:5
msgid "sys req"
msgstr "sys req"
# TRANSLATORS: name of a key
#: F:\Projects\meandmyshadow\src/dummy.h:5
msgid "break"
msgstr "break"
#: F:\Projects\meandmyshadow\src/dummy.h:5
msgid "menu"
msgstr "menu"
# TRANSLATORS: name of a key
#: F:\Projects\meandmyshadow\src/dummy.h:5
msgid "power"
msgstr "power"
# TRANSLATORS: name of a key
#: F:\Projects\meandmyshadow\src/dummy.h:5
msgid "euro"
msgstr "euro"
#: F:\Projects\meandmyshadow\src/dummy.h:5
msgid "undo"
msgstr "undo"
#, fuzzy
#~ msgid "Record times:"
#~ msgstr "记录次数:"
diff --git a/src/LevelEditSelect.cpp b/src/LevelEditSelect.cpp
index 48ccee3..16f4c97 100644
--- a/src/LevelEditSelect.cpp
+++ b/src/LevelEditSelect.cpp
@@ -1,729 +1,734 @@
/*
* Copyright (C) 2012 Me and My Shadow
*
* This file is part of Me and My Shadow.
*
* Me and My Shadow is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Me and My Shadow is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Me and My Shadow. If not, see <http://www.gnu.org/licenses/>.
*/
#include "LevelEditSelect.h"
#include "GameState.h"
#include "Functions.h"
#include "FileManager.h"
#include "Globals.h"
#include "Objects.h"
#include "GUIObject.h"
#include "GUIListBox.h"
#include "GUIScrollBar.h"
#include "InputManager.h"
+#include "StatisticsManager.h"
#include "Game.h"
#include "GUIOverlay.h"
#include <SDL/SDL_ttf.h>
#include <SDL/SDL.h>
#include <stdio.h>
#include <algorithm>
#include <string>
#include <iostream>
#include "libs/tinyformat/tinyformat.h"
using namespace std;
LevelEditSelect::LevelEditSelect():LevelSelect(_("Map Editor"),LevelPackManager::CUSTOM_PACKS){
//Create the gui.
createGUI(true);
//Set the levelEditGUIObjectRoot.
levelEditGUIObjectRoot=GUIObjectRoot;
//show level list
changePack();
refresh();
}
LevelEditSelect::~LevelEditSelect(){
selectedNumber=NULL;
}
void LevelEditSelect::createGUI(bool initial){
if(initial){
//The levelpack name text field.
levelpackName=new GUIObject(280,104,240,32,GUIObjectTextBox);
levelpackName->eventCallback=this;
levelpackName->visible=false;
GUIObjectRoot->childControls.push_back(levelpackName);
}
if(!initial){
//Remove the previous buttons.
for(int i=0;i<(int)GUIObjectRoot->childControls.size();i++){
if(GUIObjectRoot->childControls[i]->type==GUIObjectButton && GUIObjectRoot->childControls[i]->caption!=_("Back")){
delete GUIObjectRoot->childControls[i];
GUIObjectRoot->childControls.erase(GUIObjectRoot->childControls.begin()+i);
i--;
}
}
}
//Create the six buttons at the bottom of the screen.
GUIObject* obj=new GUIObject(SCREEN_WIDTH*0.02,SCREEN_HEIGHT-120,-1,32,GUIObjectButton,_("New Levelpack"));
obj->name="cmdNewLvlpack";
obj->eventCallback=this;
GUIObjectRoot->childControls.push_back(obj);
propertiesPack=new GUIObject(SCREEN_WIDTH*0.5,SCREEN_HEIGHT-120,-1,32,GUIObjectButton,_("Pack Properties"),0,true,true,GUIGravityCenter);
propertiesPack->name="cmdLvlpackProp";
propertiesPack->eventCallback=this;
GUIObjectRoot->childControls.push_back(propertiesPack);
removePack=new GUIObject(SCREEN_WIDTH*0.98,SCREEN_HEIGHT-120,-1,32,GUIObjectButton,_("Remove Pack"),0,true,true,GUIGravityRight);
removePack->name="cmdRmLvlpack";
removePack->eventCallback=this;
GUIObjectRoot->childControls.push_back(removePack);
move=new GUIObject(SCREEN_WIDTH*0.02,SCREEN_HEIGHT-60,-1,32,GUIObjectButton,_("Move Map"));
move->name="cmdMoveMap";
move->eventCallback=this;
//NOTE: Set enabled equal to the inverse of initial.
//When resizing the window initial will be false and therefor the move button can stay enabled.
move->enabled=false;
GUIObjectRoot->childControls.push_back(move);
remove=new GUIObject(SCREEN_WIDTH*0.5,SCREEN_HEIGHT-60,-1,32,GUIObjectButton,_("Remove Map"),0,false,true,GUIGravityCenter);
remove->name="cmdRmMap";
remove->eventCallback=this;
GUIObjectRoot->childControls.push_back(remove);
edit=new GUIObject(SCREEN_WIDTH*0.98,SCREEN_HEIGHT-60,-1,32,GUIObjectButton,_("Edit Map"),0,false,true,GUIGravityRight);
edit->name="cmdEdit";
edit->eventCallback=this;
GUIObjectRoot->childControls.push_back(edit);
//Now update widgets and then check if they overlap
GUIObjectRoot->render(0,0,false);
if(propertiesPack->left-propertiesPack->gravityX < obj->left+obj->width ||
propertiesPack->left-propertiesPack->gravityX+propertiesPack->width > removePack->left-removePack->gravityX){
obj->smallFont=true;
obj->width=-1;
propertiesPack->smallFont=true;
propertiesPack->width=-1;
removePack->smallFont=true;
removePack->width=-1;
move->smallFont=true;
move->width=-1;
remove->smallFont=true;
remove->width=-1;
edit->smallFont=true;
edit->width=-1;
}
//Check again
GUIObjectRoot->render(0,0,false);
if(propertiesPack->left-propertiesPack->gravityX < obj->left+obj->width ||
propertiesPack->left-propertiesPack->gravityX+propertiesPack->width > removePack->left-removePack->gravityX){
obj->left = SCREEN_WIDTH*0.02;
obj->top = SCREEN_HEIGHT-140;
obj->smallFont=false;
obj->width=-1;
obj->gravity = GUIGravityLeft;
propertiesPack->left = SCREEN_WIDTH*0.02;
propertiesPack->top = SCREEN_HEIGHT-100;
propertiesPack->smallFont=false;
propertiesPack->width=-1;
propertiesPack->gravity = GUIGravityLeft;
removePack->left = SCREEN_WIDTH*0.02;
removePack->top = SCREEN_HEIGHT-60;
removePack->smallFont=false;
removePack->width=-1;
removePack->gravity = GUIGravityLeft;
move->left = SCREEN_WIDTH*0.98;
move->top = SCREEN_HEIGHT-140;
move->smallFont=false;
move->width=-1;
move->gravity = GUIGravityRight;
remove->left = SCREEN_WIDTH*0.98;
remove->top = SCREEN_HEIGHT-100;
remove->smallFont=false;
remove->width=-1;
remove->gravity = GUIGravityRight;
edit->left = SCREEN_WIDTH*0.98;
edit->top = SCREEN_HEIGHT-60;
edit->smallFont=false;
edit->width=-1;
edit->gravity = GUIGravityRight;
}
}
void LevelEditSelect::changePack(){
packName=levelpacks->item[levelpacks->value];
if(packName=="Custom Levels"){
//Disable some levelpack buttons.
propertiesPack->enabled=false;
removePack->enabled=false;
}else{
//Enable some levelpack buttons.
propertiesPack->enabled=true;
removePack->enabled=true;
}
//Set last levelpack.
getSettings()->setValue("lastlevelpack",packName);
//Now let levels point to the right pack.
levels=getLevelPackManager()->getLevelPack(packName);
}
void LevelEditSelect::packProperties(bool newPack){
//Open a message popup.
GUIObject* root=new GUIObject((SCREEN_WIDTH-600)/2,(SCREEN_HEIGHT-320)/2,600,320,GUIObjectFrame,_("Properties"));
GUIObject* obj;
obj=new GUIObject(40,50,240,36,GUIObjectLabel,_("Name:"));
root->childControls.push_back(obj);
obj=new GUIObject(60,80,480,36,GUIObjectTextBox,packName.c_str());
if(newPack)
obj->caption="";
obj->name="LvlpackName";
root->childControls.push_back(obj);
obj=new GUIObject(40,120,240,36,GUIObjectLabel,_("Description:"));
root->childControls.push_back(obj);
obj=new GUIObject(60,150,480,36,GUIObjectTextBox,levels->levelpackDescription.c_str());
if(newPack)
obj->caption="";
obj->name="LvlpackDescription";
root->childControls.push_back(obj);
obj=new GUIObject(40,190,240,36,GUIObjectLabel,_("Congratulation text:"));
root->childControls.push_back(obj);
obj=new GUIObject(60,220,480,36,GUIObjectTextBox,levels->congratulationText.c_str());
if(newPack)
obj->caption="";
obj->name="LvlpackCongratulation";
root->childControls.push_back(obj);
obj=new GUIObject(root->width*0.3,320-44,-1,36,GUIObjectButton,_("OK"),0,true,true,GUIGravityCenter);
obj->name="cfgOK";
obj->eventCallback=this;
root->childControls.push_back(obj);
obj=new GUIObject(root->width*0.7,320-44,-1,36,GUIObjectButton,_("Cancel"),0,true,true,GUIGravityCenter);
obj->name="cfgCancel";
obj->eventCallback=this;
root->childControls.push_back(obj);
//Create the gui overlay.
GUIOverlay* overlay=new GUIOverlay(root);
if(newPack){
packName.clear();
}
}
void LevelEditSelect::addLevel(){
//Open a message popup.
GUIObject* root=new GUIObject((SCREEN_WIDTH-600)/2,(SCREEN_HEIGHT-200)/2,600,200,GUIObjectFrame,_("Add level"));
GUIObject* obj;
obj=new GUIObject(40,80,240,36,GUIObjectLabel,_("File name:"));
root->childControls.push_back(obj);
char s[64];
sprintf(s,"map%02d.map",levels->getLevelCount()+1);
obj=new GUIObject(300,80,240,36,GUIObjectTextBox,s);
obj->name="LvlFile";
root->childControls.push_back(obj);
obj=new GUIObject(root->width*0.3,200-44,-1,36,GUIObjectButton,_("OK"),0,true,true,GUIGravityCenter);
obj->name="cfgAddOK";
obj->eventCallback=this;
root->childControls.push_back(obj);
obj=new GUIObject(root->width*0.7,200-44,-1,36,GUIObjectButton,_("Cancel"),0,true,true,GUIGravityCenter);
obj->name="cfgAddCancel";
obj->eventCallback=this;
root->childControls.push_back(obj);
//Dim the screen using the tempSurface.
GUIOverlay* overlay=new GUIOverlay(root);
}
void LevelEditSelect::moveLevel(){
//Open a message popup.
GUIObject* root=new GUIObject((SCREEN_WIDTH-600)/2,(SCREEN_HEIGHT-200)/2,600,200,GUIObjectFrame,_("Move level"));
GUIObject* obj;
obj=new GUIObject(40,60,240,36,GUIObjectLabel,_("Level: "));
root->childControls.push_back(obj);
obj=new GUIObject(300,60,240,36,GUIObjectTextBox,"1");
obj->name="MoveLevel";
root->childControls.push_back(obj);
obj=new GUISingleLineListBox(root->width*0.5,110,240,36,true,true,GUIGravityCenter);
obj->name="lstPlacement";
vector<string> v;
v.push_back(_("Before"));
v.push_back(_("After"));
v.push_back(_("Swap"));
(dynamic_cast<GUISingleLineListBox*>(obj))->item=v;
obj->value=0;
root->childControls.push_back(obj);
obj=new GUIObject(root->width*0.3,200-44,-1,36,GUIObjectButton,_("OK"),0,true,true,GUIGravityCenter);
obj->name="cfgMoveOK";
obj->eventCallback=this;
root->childControls.push_back(obj);
obj=new GUIObject(root->width*0.7,200-44,-1,36,GUIObjectButton,_("Cancel"),0,true,true,GUIGravityCenter);
obj->name="cfgMoveCancel";
obj->eventCallback=this;
root->childControls.push_back(obj);
//Create the gui overlay.
GUIOverlay* overlay=new GUIOverlay(root);
}
void LevelEditSelect::refresh(bool change){
int m=levels->getLevelCount();
if(change){
numbers.clear();
//clear the selected level
if(selectedNumber!=NULL){
selectedNumber=NULL;
}
//Disable the level specific buttons.
move->enabled=false;
remove->enabled=false;
edit->enabled=false;
for(int n=0;n<=m;n++){
numbers.push_back(Number());
}
}
for(int n=0;n<m;n++){
SDL_Rect box={(n%LEVELS_PER_ROW)*64+80,(n/LEVELS_PER_ROW)*64+184,0,0};
numbers[n].init(n,box);
}
SDL_Rect box={(m%LEVELS_PER_ROW)*64+80,(m/LEVELS_PER_ROW)*64+184,0,0};
numbers[m].init("+",box);
m++; //including the "+" button
if(m>LEVELS_DISPLAYED_IN_SCREEN){
levelScrollBar->maxValue=(m-LEVELS_DISPLAYED_IN_SCREEN+LEVELS_PER_ROW-1)/LEVELS_PER_ROW;
levelScrollBar->visible=true;
}else{
levelScrollBar->maxValue=0;
levelScrollBar->visible=false;
}
if(!levels->levelpackDescription.empty())
levelpackDescription->caption=_C(levels->getDictionaryManager(),levels->levelpackDescription);
else
levelpackDescription->caption="";
}
void LevelEditSelect::selectNumber(unsigned int number,bool selected){
if(selected){
levels->setCurrentLevel(number);
setNextState(STATE_LEVEL_EDITOR);
//Pick music from the current music list.
getMusicManager()->pickMusic();
}else{
if(number==numbers.size()-1){
addLevel();
}else if(number>=0 && number<numbers.size()){
selectedNumber=&numbers[number];
//Enable the level specific buttons.
//NOTE: We check if 'remove levelpack' is enabled, if not then it's the Levels levelpack.
if(removePack->enabled)
move->enabled=true;
remove->enabled=true;
edit->enabled=true;
}
}
}
void LevelEditSelect::render(){
//Let the levelselect render.
LevelSelect::render();
}
void LevelEditSelect::resize(){
//Let the levelselect resize.
LevelSelect::resize();
//Create the GUI.
createGUI(false);
//NOTE: This is a workaround for buttons failing when resizing.
if(packName=="Custom Levels"){
removePack->enabled=false;
propertiesPack->enabled=false;
}
if(selectedNumber)
selectNumber(selectedNumber->getNumber(),false);
}
void LevelEditSelect::renderTooltip(unsigned int number,int dy){
SDL_Color fg={0,0,0};
SDL_Surface* name;
if(number==(unsigned)levels->getLevelCount()){
//Render the name of the level.
name=TTF_RenderUTF8_Blended(fontText,_("Add level"),fg);
}else{
//Render the name of the level.
name=TTF_RenderUTF8_Blended(fontText,_C(levels->getDictionaryManager(),levels->getLevelName(number)),fg);
}
//Check if name isn't null.
if(name==NULL)
return;
//Now draw a square the size of the three texts combined.
SDL_Rect r=numbers[number].box;
r.y-=dy*64;
r.w=name->w;
r.h=name->h;
//Make sure the tooltip doesn't go outside the window.
if(r.y>SCREEN_HEIGHT-200){
r.y-=name->h+4;
}else{
r.y+=numbers[number].box.h+2;
}
if(r.x+r.w>SCREEN_WIDTH-50)
r.x=SCREEN_WIDTH-50-r.w;
//Draw a rectange
Uint32 color=0xFFFFFF00|240;
drawGUIBox(r.x-5,r.y-5,r.w+10,r.h+10,screen,color);
//Calc the position to draw.
SDL_Rect r2=r;
//Now we render the name if the surface isn't null.
if(name!=NULL){
//Draw the name.
SDL_BlitSurface(name,NULL,screen,&r2);
}
//And free the surfaces.
SDL_FreeSurface(name);
}
void LevelEditSelect::GUIEventCallback_OnEvent(std::string name,GUIObject* obj,int eventType){
//NOTE: We check for the levelpack change to enable/disable some levelpack buttons.
if(name=="cmdLvlPack"){
//We call changepack and return to prevent the LevelSelect to undo what we did.
changePack();
refresh();
return;
}
//Let the level select handle his GUI events.
LevelSelect::GUIEventCallback_OnEvent(name,obj,eventType);
//Check for the edit button.
if(name=="cmdNewLvlpack"){
//Create a new pack.
packProperties(true);
}else if(name=="cmdLvlpackProp"){
//Show the pack properties.
packProperties(false);
}else if(name=="cmdRmLvlpack"){
//Show an "are you sure" message.
if(msgBox(_("Are you sure?"),MsgBoxYesNo,_("Remove prompt"))==MsgBoxYes){
//Remove the directory.
if(!removeDirectory(levels->levelpackPath.c_str())){
cerr<<"ERROR: Unable to remove levelpack directory "<<levels->levelpackPath<<endl;
}
//Remove it from the vector (levelpack list).
vector<string>::iterator it;
it=find(levelpacks->item.begin(),levelpacks->item.end(),packName);
if(it!=levelpacks->item.end()){
levelpacks->item.erase(it);
}
//Remove it from the levelpackManager.
getLevelPackManager()->removeLevelPack(packName);
//And call changePack.
levelpacks->value=levelpacks->item.size()-1;
changePack();
refresh();
}
}else if(name=="cmdMoveMap"){
if(selectedNumber!=NULL){
moveLevel();
}
}else if(name=="cmdRmMap"){
if(selectedNumber!=NULL){
if(packName!="Custom Levels"){
if(!removeFile((levels->levelpackPath+"/"+levels->getLevel(selectedNumber->getNumber())->file).c_str())){
cerr<<"ERROR: Unable to remove level "<<(levels->levelpackPath+"/"+levels->getLevel(selectedNumber->getNumber())->file).c_str()<<endl;
}
levels->removeLevel(selectedNumber->getNumber());
levels->saveLevels(levels->levelpackPath+"/levels.lst");
}else{
//This is the levels levelpack so we just remove the file.
if(!removeFile(levels->getLevel(selectedNumber->getNumber())->file.c_str())){
cerr<<"ERROR: Unable to remove level "<<levels->getLevel(selectedNumber->getNumber())->file<<endl;
}
levels->removeLevel(selectedNumber->getNumber());
}
//And refresh the selection screen.
refresh();
}
}else if(name=="cmdEdit"){
if(selectedNumber!=NULL){
levels->setCurrentLevel(selectedNumber->getNumber());
setNextState(STATE_LEVEL_EDITOR);
//Pick music from the current music list.
getMusicManager()->pickMusic();
}
}
//Check for levelpack properties events.
if(name=="cfgOK"){
//Now loop throught the children of the GUIObjectRoot in search of the fields.
for(unsigned int i=0;i<GUIObjectRoot->childControls.size();i++){
if(GUIObjectRoot->childControls[i]->name=="LvlpackName"){
//Check if the name changed.
if(packName!=GUIObjectRoot->childControls[i]->caption){
//Delete the old one.
if(!packName.empty()){
if(!renameDirectory((getUserPath(USER_DATA)+"custom/levelpacks/"+packName).c_str(),(getUserPath(USER_DATA)+"custom/levelpacks/"+GUIObjectRoot->childControls[i]->caption).c_str())){
cerr<<"ERROR: Unable to move levelpack directory "<<(getUserPath(USER_DATA)+"custom/levelpacks/"+packName)<<" to "<<(getUserPath(USER_DATA)+"custom/levelpacks/"+GUIObjectRoot->childControls[i]->caption)<<endl;
}
//Remove the old one from the levelpack manager.
getLevelPackManager()->removeLevelPack(packName);
//And the levelpack list.
vector<string>::iterator it1;
it1=find(levelpacks->item.begin(),levelpacks->item.end(),packName);
if(it1!=levelpacks->item.end()){
levelpacks->item.erase(it1);
if((unsigned)levelpacks->value>levelpacks->item.size())
levelpacks->value=levelpacks->item.size()-1;
}
}else{
//It's a new levelpack so we need to change the levels array.
LevelPack* pack=new LevelPack;
levels=pack;
//Now create the dirs.
if(!createDirectory((getUserPath(USER_DATA)+"custom/levelpacks/"+GUIObjectRoot->childControls[i]->caption).c_str())){
cerr<<"ERROR: Unable to create levelpack directory "<<(getUserPath(USER_DATA)+"custom/levelpacks/"+GUIObjectRoot->childControls[i]->caption)<<endl;
}
if(!createFile((getUserPath(USER_DATA)+"custom/levelpacks/"+GUIObjectRoot->childControls[i]->caption+"/levels.lst").c_str())){
cerr<<"ERROR: Unable to create levelpack file "<<(getUserPath(USER_DATA)+"custom/levelpacks/"+GUIObjectRoot->childControls[i]->caption+"/levels.lst")<<endl;
}
}
//And set the new name.
packName=GUIObjectRoot->childControls[i]->caption;
levels->levelpackName=packName;
levels->levelpackPath=(getUserPath(USER_DATA)+"custom/levelpacks/"+packName+"/");
//Also add the levelpack location
getLevelPackManager()->addLevelPack(levels);
levelpacks->item.push_back(GUIObjectRoot->childControls[i]->caption);
levelpacks->value=levelpacks->item.size()-1;
//And call changePack.
changePack();
}
}
if(GUIObjectRoot->childControls[i]->name=="LvlpackDescription"){
levels->levelpackDescription=GUIObjectRoot->childControls[i]->caption;
}
if(GUIObjectRoot->childControls[i]->name=="LvlpackCongratulation"){
levels->congratulationText=GUIObjectRoot->childControls[i]->caption;
}
}
//Refresh the leveleditselect to show the correct information.
refresh();
//Save the configuration.
levels->saveLevels(getUserPath(USER_DATA)+"custom/levelpacks/"+packName+"/levels.lst");
getSettings()->setValue("lastlevelpack",packName);
//Clear the gui.
if(GUIObjectRoot){
delete GUIObjectRoot;
GUIObjectRoot=NULL;
}
}else if(name=="cfgCancel"){
//Check if packName is empty, if so it was a new levelpack and we need to revert to an existing one.
if(packName.empty()){
packName=levelpacks->item[levelpacks->value];
changePack();
}
//Clear the gui.
if(GUIObjectRoot){
delete GUIObjectRoot;
GUIObjectRoot=NULL;
}
}
//Check for add level events.
if(name=="cfgAddOK"){
//Check if the file name isn't null.
//Now loop throught the children of the GUIObjectRoot in search of the fields.
for(unsigned int i=0;i<GUIObjectRoot->childControls.size();i++){
if(GUIObjectRoot->childControls[i]->name=="LvlFile"){
if(GUIObjectRoot->childControls[i]->caption.empty()){
msgBox(_("No file name given for the new level."),MsgBoxOKOnly,_("Missing file name"));
return;
}else{
string tmp_caption = GUIObjectRoot->childControls[i]->caption;
//Replace all spaces with a underline.
size_t j;
for(;(j=tmp_caption.find(" "))!=string::npos;){
tmp_caption.replace(j,1,"_");
}
//If there isn't ".map" extension add it.
size_t found=tmp_caption.find_first_of(".");
if(found!=string::npos)
tmp_caption.replace(tmp_caption.begin()+found+1,tmp_caption.end(),"map");
else if (tmp_caption.substr(found+1)!="map")
tmp_caption.append(".map");
/* Create path and file in it */
string path=(levels->levelpackPath+"/"+tmp_caption);
if(packName=="Custom Levels"){
path=(getUserPath(USER_DATA)+"/custom/levels/"+tmp_caption);
}
//First check if the file doesn't exist already.
FILE* f;
f=fopen(path.c_str(),"rb");
//Check if it exists.
if(f){
//Close the file.
fclose(f);
//Let the currentState render once to prevent multiple GUI overlapping and prevent the screen from going black.
currentState->render();
levelEditGUIObjectRoot->render();
//Notify the user.
msgBox(("The file "+tmp_caption+" already exists.").c_str(),MsgBoxOKOnly,"Error");
return;
}
if(!createFile(path.c_str())){
cerr<<"ERROR: Unable to create level file "<<path<<endl;
+ }else{
+ //Update statistics.
+ statsMgr.newAchievement("create1");
+ if((++statsMgr.createdLevels)>=50) statsMgr.newAchievement("create50");
}
levels->addLevel(path);
if(packName!="Custom Levels")
levels->saveLevels(getUserPath(USER_DATA)+"custom/levelpacks/"+packName+"/levels.lst");
refresh();
//Clear the gui.
if(GUIObjectRoot){
delete GUIObjectRoot;
GUIObjectRoot=NULL;
return;
}
}
}
}
}else if(name=="cfgAddCancel"){
//Clear the gui.
if(GUIObjectRoot){
delete GUIObjectRoot;
GUIObjectRoot=NULL;
}
}
//Check for move level events.
if(name=="cfgMoveOK"){
//Check if the entered level number is valid.
//Now loop throught the children of the GUIObjectRoot in search of the fields.
int level=0;
int placement=0;
for(unsigned int i=0;i<GUIObjectRoot->childControls.size();i++){
if(GUIObjectRoot->childControls[i]->name=="MoveLevel"){
level=atoi(GUIObjectRoot->childControls[i]->caption.c_str());
if(level<=0 || level>levels->getLevelCount()){
msgBox(_("The entered level number isn't valid!"),MsgBoxOKOnly,_("Illegal number"));
return;
}
}
if(GUIObjectRoot->childControls[i]->name=="lstPlacement"){
placement=GUIObjectRoot->childControls[i]->value;
}
}
//Now we execute the swap/move.
//Check for the place before.
if(placement==0){
//We place the selected level before the entered level.
levels->moveLevel(selectedNumber->getNumber(),level-1);
}else if(placement==1){
//We place the selected level after the entered level.
if(level<selectedNumber->getNumber())
levels->moveLevel(selectedNumber->getNumber(),level);
else
levels->moveLevel(selectedNumber->getNumber(),level+1);
}else if(placement==2){
//We swap the selected level with the entered level.
levels->swapLevel(selectedNumber->getNumber(),level-1);
}
//And save the change.
if(packName!="Custom Levels")
levels->saveLevels(getUserPath(USER_DATA)+"custom/levelpacks/"+packName+"/levels.lst");
refresh();
//Clear the gui.
if(GUIObjectRoot){
delete GUIObjectRoot;
GUIObjectRoot=NULL;
}
}else if(name=="cfgMoveCancel"){
//Clear the gui.
if(GUIObjectRoot){
delete GUIObjectRoot;
GUIObjectRoot=NULL;
}
}
}
diff --git a/src/Player.cpp b/src/Player.cpp
index 20cda2e..d731176 100644
--- a/src/Player.cpp
+++ b/src/Player.cpp
@@ -1,1361 +1,1390 @@
/*
* Copyright (C) 2011-2012 Me and My Shadow
*
* This file is part of Me and My Shadow.
*
* Me and My Shadow is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Me and My Shadow is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Me and My Shadow. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Player.h"
#include "Game.h"
#include "Functions.h"
#include "FileManager.h"
#include "Globals.h"
#include "Objects.h"
#include "InputManager.h"
+#include "StatisticsManager.h"
#include "MD5.h"
#include <iostream>
#include <fstream>
#include <SDL/SDL_mixer.h>
#include <SDL/SDL.h>
#include <SDL/SDL_ttf.h>
using namespace std;
#ifdef RECORD_FILE_DEBUG
string recordKeyPressLog,recordKeyPressLog_saved;
vector<SDL_Rect> recordPlayerPosition,recordPlayerPosition_saved;
#endif
Player::Player(Game* objParent):xVelBase(0),yVelBase(0),objParent(objParent){
//Set the dimensions of the player.
//The size of the player is 21x40.
box.x=0;
box.y=0;
box.w=21;
box.h=40;
//Set his velocity to zero.
xVel=0;
yVel=0;
//Set the start position.
fx=0;
fy=0;
//Set some default values.
inAir=true;
isJump=false;
onGround=true;
shadowCall=false;
shadow=false;
canMove=true;
holdingOther=false;
dead=false;
record=false;
downKeyPressed=false;
spaceKeyPressed=false;
recordIndex=-1;
#ifdef RECORD_FILE_DEBUG
recordKeyPressLog.clear();
recordKeyPressLog_saved.clear();
recordPlayerPosition.clear();
recordPlayerPosition_saved.clear();
#endif
objNotificationBlock=NULL;
//Some default values for animation variables.
direction=0;
jumpTime=0;
state=0;
//xVelSaved is used to store if there's a state saved or not.
xVelSaved=0x80000000;
}
Player::~Player(){
//Do nothing here
}
bool Player::isPlayFromRecord(){
return recordIndex>=0; // && recordIndex<(int)recordButton.size();
}
//get the game record object.
std::vector<int>* Player::getRecord(){
return &recordButton;
}
#ifdef RECORD_FILE_DEBUG
string& Player::keyPressLog(){
return recordKeyPressLog;
}
vector<SDL_Rect>& Player::playerPosition(){
return recordPlayerPosition;
}
#endif
//play the record.
void Player::playRecord(){
//TODO:
recordIndex=0;
}
void Player::spaceKeyDown(class Shadow* shadow){
//Start recording or stop, depending on the recording state.
if(record==false){
//We start recording.
if(shadow->called==true){
//The shadow is still busy so first stop him before we can start recording.
shadowCall=false;
shadow->called=false;
shadow->playerButton.clear();
}else if(!dead){
//The shadow isn't moving and we aren't dead so start recording.
record=true;
//We start a recording meaning we need to increase recordings by one.
objParent->recordings++;
}
}else{
//The player is recording so stop recording and call the shadow.
record=false;
shadowCall=true;
}
}
void Player::handleInput(class Shadow* shadow){
//Check if we should read the input from record file.
//Actually, we read input from record file in
//another function shadowSetState.
bool readFromRecord=false;
if(recordIndex>=0 && recordIndex<(int)recordButton.size()) readFromRecord=true;
if(!readFromRecord){
//Reset horizontal velocity.
xVel=0;
if(inputMgr.isKeyDown(INPUTMGR_RIGHT)){
//Walking to the right.
xVel+=7;
}
if(inputMgr.isKeyDown(INPUTMGR_LEFT)){
//Walking to the left.
xVel-=7;
}
//Check if a key has been released.
if(/*event.type==SDL_KEYUP || */!inputMgr.isKeyDown(INPUTMGR_ACTION)){
//It has so downKeyPressed can't be true.
downKeyPressed=false;
}
/*
//Don't reset spaceKeyPressed or when you press the space key
//and release another key then the bug occurs. (ticket #44)
if(event.type==SDL_KEYUP || !inputMgr.isKeyDown(INPUTMGR_SPACE)){
spaceKeyPressed=false;
}*/
}
//Check if a key is pressed (down).
if(inputMgr.isKeyDownEvent(INPUTMGR_JUMP) && !readFromRecord){
//The up key, if we aren't in the air we start jumping.
//Fixed a potential bug
if(!inAir && !isJump){
#ifdef RECORD_FILE_DEBUG
char c[64];
sprintf(c,"[%05d] Jump key pressed\n",objParent->time);
cout<<c;
recordKeyPressLog+=c;
#endif
isJump=true;
}
}else if(inputMgr.isKeyDownEvent(INPUTMGR_SPACE) && !readFromRecord){
//Fixed a potential bug
if(!spaceKeyPressed){
#ifdef RECORD_FILE_DEBUG
char c[64];
sprintf(c,"[%05d] Space key pressed\n",objParent->time);
cout<<c;
recordKeyPressLog+=c;
#endif
spaceKeyDown(shadow);
spaceKeyPressed=true;
}
}else if(record && !readFromRecord && inputMgr.isKeyDownEvent(INPUTMGR_CANCELRECORDING)){
//Cancel current recording
//Search the recorded button and clear the last space key press
int i=recordButton.size()-1;
for(;i>=0;i--){
if(recordButton[i] & PlayerButtonSpace){
recordButton[i] &= ~PlayerButtonSpace;
break;
}
}
if(i>=0){
//Clear the recording at the player's side.
playerButton.clear();
line.clear();
//reset the record flag
record=false;
//decrese the record count
objParent->recordings--;
}else{
cout<<"Failed to find last recording"<<endl;
}
}else if(inputMgr.isKeyDownEvent(INPUTMGR_ACTION)){
//Downkey is pressed.
//Fixed a potential bug
if(!downKeyPressed){
#ifdef RECORD_FILE_DEBUG
char c[64];
sprintf(c,"[%05d] Action key pressed\n",objParent->time);
cout<<c;
recordKeyPressLog+=c;
#endif
downKeyPressed=true;
}
}else if(inputMgr.isKeyDownEvent(INPUTMGR_SAVE)){
//F2 only works in the level editor.
if(!(dead || shadow->dead) && stateID==STATE_LEVEL_EDITOR){
//Save the state. (delayed)
if(objParent)
objParent->saveStateNextTime=true;
}
}else if(inputMgr.isKeyDownEvent(INPUTMGR_LOAD) && !readFromRecord){
//F3 is used to load the last state.
if(objParent)
objParent->loadStateNextTime=true;
}else if(inputMgr.isKeyDownEvent(INPUTMGR_SWAP)){
//F4 will swap the player and the shadow, but only in the level editor.
if(!(dead || shadow->dead) && stateID==STATE_LEVEL_EDITOR){
swapState(shadow);
}
}else if(inputMgr.isKeyDownEvent(INPUTMGR_TELEPORT)){
//F5 will revive and teleoprt the player to the cursor. Only works in the level editor.
//Shift+F5 teleports the shadow.
if(stateID==STATE_LEVEL_EDITOR){
//get the position of the cursor.
int x,y;
SDL_GetMouseState(&x,&y);
x+=camera.x;
y+=camera.y;
if(inputMgr.isKeyDown(INPUTMGR_SHIFT)){
//teleports the shadow.
shadow->dead=false;
shadow->box.x=x;
shadow->box.y=y;
}else{
//teleports the player.
dead=false;
box.x=x;
box.y=y;
}
//play sound?
if(getSettings()->getBoolValue("sound")){
Mix_PlayChannel(-1,swapSound,0);
}
}
}else if(inputMgr.isKeyDownEvent(INPUTMGR_SUICIDE)){
//F12 is suicide and only works in the leveleditor.
if(stateID==STATE_LEVEL_EDITOR){
die();
shadow->die();
}
}
}
void Player::setPosition(int x,int y){
box.x=x;
box.y=y;
}
void Player::move(vector<GameObject*> &levelObjects){
//Pointer to a checkpoint.
GameObject* objCheckPoint=NULL;
//Pointer to a swap.
GameObject* objSwap=NULL;
//Set the objShadowBlock to NULL.
//Only for swapping to prevent the shadow from swapping in a shadow block.
objShadowBlock=NULL;
//Set the objNotificationBlock to NULL.
objNotificationBlock=NULL;
//Boolean if the player can teleport.
bool canTeleport=true;
//Set the object the player is currently standing to NULL.
objCurrentStand=NULL;
//Check if the player is still alive.
if(dead==false){
//Add gravity
if(inAir==true){
yVel+=1;
//Cap fall speed to 13.
if(yVel>13){
yVel=13;
}
}
//Boolean if the player is moved, used for squash detection.
bool playerMoved=false;
//The current location of the player, used to set the player back if he's squashed to prevent displacement.
int lastX=box.x;
int lastY=box.y;
//Check if the player can move.
if(canMove==true){
//Check if the player is moving or not.
if(xVel>0){
direction=0;
onGround=false;
if(appearance.currentStateName!="walkright"){
appearance.changeState("walkright");
}
}else if(xVel<0){
direction=1;
onGround=false;
if(appearance.currentStateName!="walkleft"){
appearance.changeState("walkleft");
}
}else if(xVel==0){
onGround=true;
if(direction==1){
appearance.changeState("standleft");
}else{
appearance.changeState("standright");
}
}
//Move the player.
box.x+=xVel;
//Loop through the levelobjects.
for(unsigned int o=0; o<levelObjects.size(); o++){
//Check if the player can walk on the object.
if(levelObjects[o]->queryProperties(GameObjectProperty_PlayerCanWalkOn,this)){
//Get the collision box of the levelobject.
SDL_Rect r=levelObjects[o]->getBox();
//Check collision with the player.
if(checkCollision(box,r)){
//We have collision, get the velocity of the box.
SDL_Rect v=levelObjects[o]->getBox(BoxType_Delta);
//Check on which side of the box the player is.
if(box.x + box.w/2 <= r.x + r.w/2){
//The left side of the block.
if(xVel+xVelBase>v.x){
if(box.x>r.x-box.w){
box.x=r.x-box.w;
playerMoved=true;
}
}
}else{
//The right side of the block.
if(xVel+xVelBase<v.x){
if(box.x<r.x+r.w){
box.x=r.x+r.w;
playerMoved=true;
}
}
}
}
}
}
}
//Now apply the yVel. (gravity, jumping, etc..)
box.y+=yVel;
//Pointer to the object the player standed on.
GameObject* lastStand=NULL;
//???
inAir=true;
canMove=true;
//Loop through all the levelObjects.
for(unsigned int o=0; o<levelObjects.size(); o++){
//Check if the object is solid.
if(levelObjects[o]->queryProperties(GameObjectProperty_PlayerCanWalkOn,this)){
SDL_Rect r=levelObjects[o]->getBox();
if(checkCollision(r,box)==true){ //TODO:fix some bug
SDL_Rect v=levelObjects[o]->getBox(BoxType_Delta);
if(box.y+box.h/2<=r.y+r.h/2){
if(yVel>=v.y || yVel>=0){
inAir=false;
box.y=r.y-box.h;
yVel=1; //???
lastStand=levelObjects[o];
lastStand->onEvent(GameObjectEvent_PlayerIsOn);
//The player is moved, if it's a moving block check for squating.
if(v.y!=0){
playerMoved=true;
}
}
}else{
//FIXME: The player can have a yVel of 0 and get squashed if he is standing on the other.
bool holding=objParent->shadow.holdingOther;
if(shadow)
holding=objParent->player.holdingOther;
if(yVel<=v.y+1 || holding){
yVel=v.y>0?v.y:0;
if(box.y<r.y+r.h){
if(!holding)
box.y=r.y+r.h;
//The player is moved, if it's a moving block check for squating.
if(v.y!=0){
playerMoved=true;
}
}
}
}
}
}
//Check if the object is a checkpoint.
if(levelObjects[o]->type==TYPE_CHECKPOINT && checkCollision(box,levelObjects[o]->getBox())){
//If we're not the shadow set the gameTip to Checkpoint.
if(!shadow && objParent!=NULL)
objParent->gameTipIndex=TYPE_CHECKPOINT;
//And let objCheckPoint point to this object.
objCheckPoint=levelObjects[o];
}
//Check if the object is a swap.
if(levelObjects[o]->type==TYPE_SWAP && checkCollision(box,levelObjects[o]->getBox())){
//If we're not the shadow set the gameTip to swap.
if(!shadow && objParent!=NULL)
objParent->gameTipIndex=TYPE_SWAP;
//And let objSwap point to this object.
objSwap=levelObjects[o];
}
//Check if the object is an exit.
//This doesn't work if the state is Level editor.
if(levelObjects[o]->type==TYPE_EXIT && stateID!=STATE_LEVEL_EDITOR && checkCollision(box,levelObjects[o]->getBox())){
//Check to see if we have enough keys to finish the level
if (objParent->currentCollectables>=objParent->totalCollectables){
//We can't just handle the winning here (in the middle of the update cycle)/
//So set won in Game true.
objParent->won=true;
}
}
//Check if the object is a portal.
if(levelObjects[o]->type==TYPE_PORTAL && checkCollision(box,levelObjects[o]->getBox())){
//Check if the teleport id isn't empty.
if((dynamic_cast<Block*>(levelObjects[o]))->id.empty()){
cerr<<"Warning: Invalid teleport id!"<<endl;
canTeleport=false;
}
//If we're not the shadow set the gameTip to portal.
if(!shadow && objParent!=NULL)
objParent->gameTipIndex=TYPE_PORTAL;
//Check if we can teleport and should (downkey -or- auto).
if(canTeleport && (downKeyPressed || (levelObjects[o]->queryProperties(GameObjectProperty_Flags,this)&1))){
canTeleport=false;
if(downKeyPressed || levelObjects[o]!=objLastTeleport){
downKeyPressed=false;
//Loop the levelobjects again to find the destination.
for(unsigned int oo=o+1;;){
//We started at our index+1.
//Meaning that if we reach the end of the vector then we need to start at the beginning.
if(oo>=levelObjects.size())
oo-=(int)levelObjects.size();
//It also means that if we reach the same index we need to stop.
//If the for loop breaks this way then we have no succes.
if(oo==o){
//Couldn't teleport so play the error sound.
if(getSettings()->getBoolValue("sound")){
Mix_PlayChannel(-1,errorSound,0);
}
break;
}
//Check if the second (oo) object is a portal.
if(levelObjects[oo]->type==TYPE_PORTAL){
//Check the id against the destination of the first portal.
if((dynamic_cast<Block*>(levelObjects[o]))->destination==(dynamic_cast<Block*>(levelObjects[oo]))->id){
//Call the event.
levelObjects[o]->onEvent(GameObjectEvent_OnToggle);
objLastTeleport=levelObjects[oo];
//Get the destination location and teleport the player.
SDL_Rect r=levelObjects[oo]->getBox();
box.x=r.x+5;
box.y=r.y+2;
//Check if music/sound is enabled.
if(getSettings()->getBoolValue("sound")){
Mix_PlayChannel(-1,swapSound,0);
}
break;
}
}
//Increase oo.
oo++;
}
}
}
}
//Check if the object is a switch.
if(levelObjects[o]->type==TYPE_SWITCH && checkCollision(box,levelObjects[o]->getBox())){
//If we're not the shadow set the gameTip to switch.
if(!shadow && objParent!=NULL)
objParent->gameTipIndex=TYPE_SWITCH;
//If the down key is pressed then invoke an event.
if(downKeyPressed){
//Play the animation.
levelObjects[o]->playAnimation(1);
//Check if sound is enabled, if so play the toggle sound.
if(getSettings()->getBoolValue("sound")==true){
Mix_PlayChannel(-1,toggleSound,0);
}
if(objParent!=NULL){
//Make sure that the id isn't emtpy.
if(!(dynamic_cast<Block*>(levelObjects[o]))->id.empty()){
objParent->broadcastObjectEvent(0x10000 | (levelObjects[o]->queryProperties(GameObjectProperty_Flags,this)&3),
-1,(dynamic_cast<Block*>(levelObjects[o]))->id.c_str());
}else{
cerr<<"Warning: invalid switch id!"<<endl;
}
}
}
}
//Check if the object is a shadow block, only if we are the player.
if((levelObjects[o]->type==TYPE_SHADOW_BLOCK || levelObjects[o]->type==TYPE_MOVING_SHADOW_BLOCK) && checkCollision(box,levelObjects[o]->getBox()) && !shadow){
objShadowBlock=levelObjects[o];
}
//Check if the object is a notification block, only if we are the player.
if(levelObjects[o]->type==TYPE_NOTIFICATION_BLOCK && checkCollision(box,levelObjects[o]->getBox()) && !shadow){
objNotificationBlock=levelObjects[o];
}
//Check if the object is a collectable
if(levelObjects[o]->type==TYPE_COLLECTABLE && checkCollision(box,levelObjects[o]->getBox())){
//Check if collectable is active (if it's not it's equal to 1(inactive))
if (levelObjects[o]->queryProperties(GameObjectProperty_Flags, this)==0) {
//Toggle an event
levelObjects[o]->onEvent(GameObjectEvent_OnToggle);
//Increase the current number of collectables
objParent->currentCollectables++;
if(getSettings()->getBoolValue("sound"))
Mix_PlayChannel(-1,collectSound,0);
//Open exit(s)
if (objParent->currentCollectables>=objParent->totalCollectables){
for(unsigned int i=0;i<levelObjects.size();i++){
if(levelObjects[i]->type==TYPE_EXIT){
Block *obj=dynamic_cast<Block*>(levelObjects[i]);
if(obj!=NULL){
levelObjects[i]->onEvent(GameObjectEvent_OnSwitchOn);
}
}
}
}
}
}
//Check if the object is deadly.
if(levelObjects[o]->queryProperties(GameObjectProperty_IsSpikes,this)){
//It is so get the collision box.
SDL_Rect r=levelObjects[o]->getBox();
//TODO: pixel-accuracy hit test.
//For now we shrink the box.
r.x+=2;
r.y+=2;
r.w-=4;
r.h-=4;
//Check collision, if the player collides then let him die.
if(checkCollision(box,r)){
//Now make sure we don't collide with a different block.
for(unsigned int oo=o+1;;){
//We started at our index+1.
//Meaning that if we reach the end of the vector then we need to start at the beginning.
if(oo>=levelObjects.size())
oo-=(int)levelObjects.size();
//It also means that if we reach the same index we need to stop.
//If the for loop breaks this way then we have no succes.
if(oo==o){
//Nothing found so call the die method.
die();
break;
}
//Check if the second (oo) object is a block.
if(levelObjects[oo]->queryProperties(GameObjectProperty_PlayerCanWalkOn,this)){
//Get the collision box.
SDL_Rect r2=levelObjects[oo]->getBox();
if(checkCollision(box,r2)){
//Check if the top isn't covered.
if(r2.y>r.y){
//It isn't covered so create a box for collision detection
SDL_Rect tmp={r2.x,r2.y,r2.w,r2.y-r.y};
if(checkCollision(box,tmp)){
//We hit spikes so die?
die();
break;
}
}
//Check if the left side isn't covered.
if(r2.x>r.x){
//It isn't covered so create a box for collision detection
SDL_Rect tmp={r2.x,r2.y,r2.x-r.x,r2.h};
if(checkCollision(box,tmp)){
//We hit spikes so die?
die();
break;
}
}
//Check if the right side isn't covered.
if(r2.x+r2.w>r.x+r.w){
//It isn't covered so create a box for collision detection
SDL_Rect tmp={r.x+r.w,r2.y,(r2.x+r2.w)-(r.x+r.w),r2.h};
if(checkCollision(box,tmp)){
//We hit spikes so die?
die();
break;
}
}
//Check if the bottom isn't covered.
if(r2.y+r2.h>r.y+r.h){
//It isn't covered so create a box for collision detection
SDL_Rect tmp={r2.x,r.y+r.h,r2.w,(r2.y+r2.h)-(r.y+r.h)};
if(checkCollision(box,tmp)){
//We hit spikes so die?
die();
break;
}
}
//Check collision with the player and the block and with the block and the spikes.
if(checkCollision(box,r)){
//We break the loop to prevent going round (and calling the die() method).
break;
}
}
}
//Increase oo.
oo++;
}
}
}
}
//Check if the player was moved, if so check if the player is squashed.
if(playerMoved){
for(unsigned int o=0;o<levelObjects.size();o++){
SDL_Rect r2=levelObjects[o]->getBox();
if(levelObjects[o]->queryProperties(GameObjectProperty_PlayerCanWalkOn,this) && checkCollision(box,r2)){
//The player is squashed so first move him back.
box.x=lastX;
box.y=lastY;
//Now call the die method.
die();
}
}
}
//Check if the player fell of the level, if so let him die but without animation.
if(box.y>LEVEL_HEIGHT)
die(false);
//Check if the player changed blocks, meaning stepped onto a block.
objCurrentStand=lastStand;
if(lastStand!=objLastStand){
objLastStand=lastStand;
if(lastStand){
//Call the walk on event of the laststand.
lastStand->onEvent(GameObjectEvent_PlayerWalkOn);
//Bugfix for Fragile blocks.
if(lastStand->type==TYPE_FRAGILE && !lastStand->queryProperties(GameObjectProperty_PlayerCanWalkOn,this)){
inAir=true;
onGround=false;
isJump=false;
}
}
}
//Check if the player can teleport.
if(canTeleport)
objLastTeleport=NULL;
//Check the checkpoint pointer only if the downkey is pressed.
//new: don't save the game if playing game record
if(objParent!=NULL && downKeyPressed && objCheckPoint!=NULL && !isPlayFromRecord()){
//Checkpoint thus save the state.
if(objParent->canSaveState()){
objParent->saveStateNextTime=true;
objParent->objLastCheckPoint=objCheckPoint;
}
}
//Check the swap pointer only if the down key is pressed.
if(objSwap!=NULL && downKeyPressed && objParent!=NULL){
//Now check if the shadow we're the shadow or not.
if(shadow){
if(!(dead || objParent->player.dead)){
//Check if the player isn't in front of a shadow block.
if(!objParent->player.objShadowBlock){
objParent->player.swapState(this);
objSwap->playAnimation(1);
}else{
//We can't swap so play the error sound.
if(getSettings()->getBoolValue("sound")==true){
Mix_PlayChannel(-1,errorSound,0);
}
}
}
}else{
if(!(dead || objParent->shadow.dead)){
//Check if the player isn't in front of a shadow block.
if(!objShadowBlock){
swapState(&objParent->shadow);
objSwap->playAnimation(1);
}else{
//We can't swap so play the error sound.
if(getSettings()->getBoolValue("sound")==true){
Mix_PlayChannel(-1,errorSound,0);
}
}
}
}
}
//Check for jump appearance (inAir).
if(inAir && !dead){
if(direction==1){
if(yVel>0){
if(appearance.currentStateName!="fallleft")
appearance.changeState("fallleft");
}else{
if(appearance.currentStateName!="jumpleft")
appearance.changeState("jumpleft");
}
}else{
if(yVel>0){
if(appearance.currentStateName!="fallright")
appearance.changeState("fallright");
}else{
if(appearance.currentStateName!="jumpright")
appearance.changeState("jumpright");
}
}
}
}
//Finally we reset some stuff.
downKeyPressed=false;
xVelBase=0;
yVelBase=0;
}
void Player::jump(){
//Check if the player is dead or not.
if(dead==true){
//The player can't jump if he's dead.
isJump=false;
}
//Check if the player can jump.
if(isJump==true && inAir==false){
//Set the jump velocity.
yVel=-13;
inAir=true;
isJump=false;
jumpTime++;
+ //Update statistics
+ if(!objParent->player.isPlayFromRecord() && !objParent->interlevel){
+ if(shadow) statsMgr.shadowJumps++;
+ else statsMgr.playerJumps++;
+
+ if(statsMgr.playerJumps+statsMgr.shadowJumps==1000) statsMgr.newAchievement("frog");
+ }
+
//Check if sound is enabled, if so play the jump sound.
if(getSettings()->getBoolValue("sound")==true){
Mix_PlayChannel(-1,jumpSound,0);
}
}
}
void Player::show(){
//Check if we should render the recorded line.
//Only do this when we're recording and we're not the shadow.
if(shadow==false && record==true){
//FIXME: Adding an entry not in update but in render?
line.push_back(SDL_Rect());
line[line.size()-1].x=box.x+11;
line[line.size()-1].y=box.y+20;
//Loop through the line dots and draw them.
for(int l=0; l<(signed)line.size(); l++){
appearance.drawState("line",screen,line[l].x-camera.x,line[l].y-camera.y,NULL);
}
}
//NOTE: We do logic here, because it's only needed by the appearance.
appearance.updateAnimation();
appearance.draw(screen, box.x-camera.x, box.y-camera.y, NULL);
}
void Player::shadowSetState(){
int currentKey=0;
/*//debug
extern int block_test_count;
extern bool block_test_only;
if(SDL_GetKeyState(NULL)[SDLK_p]){
block_test_count=recordButton.size();
}
if(block_test_count==(int)recordButton.size()){
block_test_only=true;
}*/
//Check if we should read the input from record file.
if(recordIndex>=0){ // && recordIndex<(int)recordButton.size()){
//read the input from record file
if(recordIndex<(int)recordButton.size()){
currentKey=recordButton[recordIndex];
recordIndex++;
}
//Reset horizontal velocity.
xVel=0;
if(currentKey&PlayerButtonRight){
//Walking to the right.
xVel+=7;
}
if(currentKey&PlayerButtonLeft){
//Walking to the left.
xVel-=7;
}
if(currentKey&PlayerButtonJump){
//The up key, if we aren't in the air we start jumping.
if(inAir==false){
isJump=true;
}else{
//Shouldn't go here
cout<<"Replay BUG"<<endl;
}
}
//check the down key
downKeyPressed=(currentKey&PlayerButtonDown)!=0;
//check the space key
if(currentKey&PlayerButtonSpace){
spaceKeyDown(&objParent->shadow);
}
}else{
//read the input from keyboard.
recordIndex=-1;
//Check for xvelocity.
if(xVel>0)
currentKey|=PlayerButtonRight;
if(xVel<0)
currentKey|=PlayerButtonLeft;
//Check for jumping.
if(isJump){
#ifdef RECORD_FILE_DEBUG
char c[64];
sprintf(c,"[%05d] Jump key recorded\n",objParent->time-1);
cout<<c;
recordKeyPressLog+=c;
#endif
currentKey|=PlayerButtonJump;
}
//Check if the downbutton is pressed.
if(downKeyPressed){
#ifdef RECORD_FILE_DEBUG
char c[64];
sprintf(c,"[%05d] Action key recorded\n",objParent->time-1);
cout<<c;
recordKeyPressLog+=c;
#endif
currentKey|=PlayerButtonDown;
}
if(spaceKeyPressed){
#ifdef RECORD_FILE_DEBUG
char c[64];
sprintf(c,"[%05d] Space key recorded\n",objParent->time-1);
cout<<c;
recordKeyPressLog+=c;
#endif
currentKey|=PlayerButtonSpace;
}
//Record it.
recordButton.push_back(currentKey);
}
#ifdef RECORD_FILE_DEBUG
if(recordIndex>=0){
if(recordIndex>0 && recordIndex<=int(recordPlayerPosition.size())/2){
SDL_Rect &r1=recordPlayerPosition[recordIndex*2-2];
SDL_Rect &r2=recordPlayerPosition[recordIndex*2-1];
if(r1.x!=box.x || r1.y!=box.y || r2.x!=objParent->shadow.box.x || r2.y!=objParent->shadow.box.y){
char c[192];
sprintf(c,"Replay ERROR [%05d] %d %d %d %d Expected: %d %d %d %d\n",
objParent->time-1,box.x,box.y,objParent->shadow.box.x,objParent->shadow.box.y,r1.x,r1.y,r2.x,r2.y);
cout<<c;
}
}
}else{
recordPlayerPosition.push_back(box);
recordPlayerPosition.push_back(objParent->shadow.box);
}
#endif
//reset spaceKeyPressed.
spaceKeyPressed=false;
//Only add an entry if the player is recording.
if(record){
//Add the action.
if(!dead){
playerButton.push_back(currentKey);
//Change the state.
state++;
}
}
}
void Player::shadowGiveState(Shadow* shadow){
//Check if the player calls the shadow.
if(shadowCall==true){
//Clear any recording still with the shadow.
shadow->playerButton.clear();
//Loop the recorded moves and add them to the one of the shadow.
for(unsigned int s=0;s<playerButton.size();s++){
shadow->playerButton.push_back(playerButton[s]);
}
//Reset the state of both the player and the shadow.
stateReset();
shadow->stateReset();
//Clear the recording at the player's side.
playerButton.clear();
line.clear();
//Set shadowCall false
shadowCall=false;
//And let the shadow know that the player called him.
shadow->meCall();
}
}
void Player::stateReset(){
//Reset the state by setting it to 0.
state=0;
}
void Player::otherCheck(class Player* other){
//First make sure the player isn't dead.
//And check for velocity of the block the player is standing on.
if(!dead){
if(objCurrentStand!=NULL){
//Now get the velocity of the object the player is standing on.
SDL_Rect v=objCurrentStand->getBox(BoxType_Velocity);
//Set the base velocity to the velocity of the object.
xVelBase=v.x;
yVelBase=v.y;
//Already move the player box.
box.x+=v.x;
box.y+=v.y;
}
}
//Now do the same for the shadow.
if(!other->dead){
if(other->objCurrentStand!=NULL){
//Now get the velocity of the object the shadow is standing on.
SDL_Rect v=other->objCurrentStand->getBox(BoxType_Velocity);
//Set the base velocity to the velocity of the object.
other->xVelBase=v.x;
other->yVelBase=v.y;
//Already move the shadow box.
other->box.x+=v.x;
other->box.y+=v.y;
}
}
//Now check if the player is on the shadow.
//First make sure they are both alive.
if(!dead && !other->dead){
//Get the box of the shadow.
SDL_Rect boxShadow=other->getBox();
//Check if the player is on top of the shadow.
if(checkCollision(box,boxShadow)==true){
//We have collision now check if the other is standing on top of you.
if(box.y+box.h<=boxShadow.y+13 && !other->inAir){
int yVelocity=yVel-1;
if(yVelocity>0){
box.y-=yVel;
box.y+=boxShadow.y-(box.y+box.h);
inAir=false;
canMove=false;
onGround=true;
other->holdingOther=true;
other->appearance.changeState("holding");
//Change our own appearance to standing.
if(direction==1){
appearance.changeState("standleft");
}else{
appearance.changeState("standright");
}
//Apply the velocity the shadow has.
box.x+=other->xVelBase;
box.y+=other->yVelBase;
}
}else if(boxShadow.y+boxShadow.h<=box.y+13 && !inAir){
int yVelocity=other->yVel-1;
if(yVelocity>0){
other->box.y-=other->yVel;
other->box.y+=box.y-(other->box.y+other->box.h);
other->inAir=false;
other->canMove=false;
other->onGround=true;
holdingOther=true;
appearance.changeState("holding");
//Change our own appearance to standing.
if(other->direction==1){
other->appearance.changeState("standleft");
}else{
other->appearance.changeState("standright");
}
//Apply the velocity the shadow has.
other->box.x+=xVelBase;
other->box.y+=yVelBase;
}
}
}else{
holdingOther=false;
other->holdingOther=false;
}
}
//And set currentStand to null.
objCurrentStand=NULL;
other->objCurrentStand=NULL;
}
SDL_Rect Player::getBox(){
return box;
}
void Player::setMyCamera(){
//Only change the camera when the player isn't dead.
if(dead)
return;
//Check if the level fit's horizontally inside the camera.
if(camera.w>LEVEL_WIDTH){
camera.x=-(camera.w-LEVEL_WIDTH)/2;
}else{
//Check if the player is halfway pass the halfright of the screen.
if(box.x>camera.x+(SCREEN_WIDTH/2+50)){
//It is so ease the camera to the right.
camera.x+=(box.x-camera.x-(SCREEN_WIDTH/2))>>4;
//Check if the camera isn't going too far.
if(box.x<camera.x+(SCREEN_WIDTH/2+50)){
camera.x=box.x-(SCREEN_WIDTH/2+50);
}
}
//Check if the player is halfway pass the halfleft of the screen.
if(box.x<camera.x+(SCREEN_WIDTH/2-50)){
//It is so ease the camera to the left.
camera.x+=(box.x-camera.x-(SCREEN_WIDTH/2))>>4;
//Check if the camera isn't going too far.
if(box.x>camera.x+(SCREEN_WIDTH/2-50)){
camera.x=box.x-(SCREEN_WIDTH/2-50);
}
}
//If the camera is too far to the left we set it to 0.
if(camera.x<0){
camera.x=0;
}
//If the camera is too far to the right we set it to the max right.
if(camera.x+camera.w>LEVEL_WIDTH){
camera.x=LEVEL_WIDTH-camera.w;
}
}
//Check if the level fit's vertically inside the camera.
if(camera.h>LEVEL_HEIGHT){
//We don't centre vertical because the bottom line of the level (deadly) will be mid air.
camera.y=-(camera.h-LEVEL_HEIGHT);
}else{
//Check if the player is halfway pass the lower half of the screen.
if(box.y>camera.y+(SCREEN_HEIGHT/2+50)){
//If is so ease the camera down.
camera.y+=(box.y-camera.y-(SCREEN_HEIGHT/2))>>4;
//Check if the camera isn't going too far.
if(box.y<camera.y+(SCREEN_HEIGHT/2+50)){
camera.y=box.y-(SCREEN_HEIGHT/2+50);
}
}
//Check if the player is halfway pass the upper half of the screen.
if(box.y<camera.y+(SCREEN_HEIGHT/2-50)){
//It is so ease the camera up.
camera.y+=(box.y-camera.y-(SCREEN_HEIGHT/2))>>4;
//Check if the camera isn't going too far.
if(box.y>camera.y+(SCREEN_HEIGHT/2-50)){
camera.y=box.y-(SCREEN_HEIGHT/2-50);
}
}
//If the camera is too far up we set it to 0.
if(camera.y<0){
camera.y=0;
}
//If the camera is too far down we set it to the max down.
if(camera.y+camera.h>LEVEL_HEIGHT){
camera.y=LEVEL_HEIGHT-camera.h;
}
}
}
void Player::reset(bool save){
//Set the location of the player to it's initial state.
box.x=fx;
box.y=fy;
//Reset back to default value.
inAir=true;
isJump=false;
onGround=true;
shadowCall=false;
canMove=true;
holdingOther=false;
dead=false;
record=false;
downKeyPressed=false;
spaceKeyPressed=false;
//Some animation variables.
appearance.resetAnimation(save);
appearance.changeState("standright");
direction=0;
state=0;
xVel=0; //??? fixed a strange bug in game replay
yVel=0;
objCurrentStand=NULL;
objNotificationBlock=NULL;
//Clear the recording.
line.clear();
playerButton.clear();
recordButton.clear();
recordIndex=-1;
#ifdef RECORD_FILE_DEBUG
recordKeyPressLog.clear();
recordPlayerPosition.clear();
#endif
//xVelSaved is used to indicate if there's a state saved or not.
if(save){
xVelSaved=0x80000000;
}
}
void Player::saveState(){
//We can only save the state when the player isn't dead.
if(!dead){
boxSaved.x=box.x;
boxSaved.y=box.y;
xVelSaved=xVel;
yVelSaved=yVel;
inAirSaved=inAir;
isJumpSaved=isJump;
onGroundSaved=onGround;
canMoveSaved=canMove;
holdingOtherSaved=holdingOther;
stateSaved=state;
//Let the appearance save.
appearance.saveAnimation();
//Save any recording stuff.
recordSaved=record;
playerButtonSaved=playerButton;
lineSaved=line;
//Save the record
savedRecordButton=recordButton;
#ifdef RECORD_FILE_DEBUG
recordKeyPressLog_saved=recordKeyPressLog;
recordPlayerPosition_saved=recordPlayerPosition;
#endif
//Only play the sound when it's enabled.
if(getSettings()->getBoolValue("sound")==true){
//To prevent playing the sound twice, only the player can cause the sound.
if(!shadow)
Mix_PlayChannel(-1,saveSound,0);
}
}
}
void Player::loadState(){
//Check with xVelSaved if there's a saved state.
if(xVelSaved==int(0x80000000)){
//There isn't so reset the game to load the first initial state.
//NOTE: There's no need in removing the saved state since there is none.
reset(false);
return;
}
//Restore the saved values.
box.x=boxSaved.x;
box.y=boxSaved.y;
//xVel is set to 0 since it's saved counterpart is used to indicate a saved state.
xVel=0;
yVel=yVelSaved;
//Restore the saved values.
inAir=inAirSaved;
isJump=isJumpSaved;
onGround=onGroundSaved;
canMove=canMoveSaved;
holdingOther=holdingOtherSaved;
dead=false;
record=false;
shadowCall=false;
state=stateSaved;
//Restore the appearance.
appearance.loadAnimation();
//Restore any recorded stuff.
record=recordSaved;
playerButton=playerButtonSaved;
line=lineSaved;
//Load the previously saved record
recordButton=savedRecordButton;
#ifdef RECORD_FILE_DEBUG
recordKeyPressLog=recordKeyPressLog_saved;
recordPlayerPosition=recordPlayerPosition_saved;
#endif
}
void Player::swapState(Player* other){
//We need to swap the values of the player with the ones of the given player.
swap(box.x,other->box.x);
swap(box.y,other->box.y);
//NOTE: xVel isn't there since it's used for something else.
swap(yVel,other->yVel);
swap(inAir,other->inAir);
swap(isJump,other->isJump);
swap(onGround,other->onGround);
swap(canMove,other->canMove);
swap(holdingOther,other->holdingOther);
swap(dead,other->dead);
//Also reset the state of the other.
other->stateReset();
//Play the swap sound.
if(getSettings()->getBoolValue("sound")==true){
Mix_PlayChannel(-1,swapSound,0);
}
}
bool Player::canSaveState(){
//We can only save the state if the player isn't dead.
return !dead;
}
bool Player::canLoadState(){
//We use xVelSaved to indicate if a state is saved or not.
return xVelSaved != int(0x80000000);
}
void Player::die(bool animation){
//Make sure the player isn't already dead.
if(!dead){
dead=true;
//If sound is enabled run the hit sound.
if(getSettings()->getBoolValue("sound")==true){
Mix_PlayChannel(-1,hitSound,0);
}
//Change the apearance to die (if animation is true).
if(animation){
if(appearance.currentStateName.find("right")!=std::string::npos){
appearance.changeState("dieright");
}else{
appearance.changeState("dieleft");
}
}
+
+ //Update statistics
+ if(!objParent->player.isPlayFromRecord() && !objParent->interlevel){
+ if(shadow) statsMgr.shadowDies++;
+ else statsMgr.playerDies++;
+
+ switch(statsMgr.playerDies+statsMgr.shadowDies){
+ case 1:
+ statsMgr.newAchievement("die1");
+ break;
+ case 50:
+ statsMgr.newAchievement("die50");
+ break;
+ case 1000:
+ statsMgr.newAchievement("die1000");
+ break;
+ }
+
+ if(objParent->player.dead && objParent->shadow.dead) statsMgr.newAchievement("doubleKill");
+ }
}
//We set the jumpTime to 120 when this is the shadow.
//That's the countdown for the "Your shadow has died." message.
if(shadow){
jumpTime=80;
}
}
diff --git a/src/StatisticsManager.cpp b/src/StatisticsManager.cpp
index 768bd06..8247e0c 100644
--- a/src/StatisticsManager.cpp
+++ b/src/StatisticsManager.cpp
@@ -1,570 +1,594 @@
/*
* Copyright (C) 2012 Me and My Shadow
*
* This file is part of Me and My Shadow.
*
* Me and My Shadow is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Me and My Shadow is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Me and My Shadow. If not, see <http://www.gnu.org/licenses/>.
*/
#include "StatisticsManager.h"
#include "FileManager.h"
#include "TreeStorageNode.h"
#include "POASerializer.h"
#include "Functions.h"
#include "LevelPackManager.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <iostream>
#include <fstream>
#include <vector>
#include <map>
using namespace std;
StatisticsManager statsMgr;
static const int achievementDisplayTime=100;
static const int achievementIntervalTime=120;
//internal struct for achievement info
struct AchievementInfo{
//achievement id for save to statistics file
const char* id;
//achievement name for display
const char* name;
//achievement image. NULL for no image. will be loaded at getDataPath()+imageFile
const char* imageFile;
//SDL_Surface of achievement image.
SDL_Surface* imageSurface;
//image offset and size.
SDL_Rect r;
//achievement description. supports multi-line text
const char* description;
};
static AchievementInfo achievementList[]={
{"newbie",__("Newbie"),"themes/Cloudscape/player.png",NULL,{0,0,23,40},__("Congratulations, you completed one level!")},
{"experienced",__("Experienced player"),"themes/Cloudscape/player.png",NULL,{0,0,23,40},__("Completed 50 levels.")},
{"goodjob",__("Good job!"),"gfx/medals.png",NULL,{60,0,30,30},__("Get your first gold medal.")},
{"expert",__("Expert"),"gfx/medals.png",NULL,{60,0,30,30},__("Earned 50 gold medal.")},
{"tutorial",__("Graduate"),"gfx/medals.png",NULL,{60,0,30,30},__("Complete the tutorial level pack.")},
{"tutorialGold",__("Outstanding graduate"),"gfx/medals.png",NULL,{60,0,30,30},__("Complete the tutorial level pack with all levels gold medal.")},
{"addicted",__("Addicted"),"themes/Cloudscape/player.png",NULL,{0,0,23,40},__("Played Me and My Shadow for more than 2 hours.")},
{"loyalFan",__("Me and My Shadow loyal fan"),"themes/Cloudscape/player.png",NULL,{0,0,23,40},__("Played Me and My Shadow for more than 24 hours.")},
{"constructor",__("Constructor"),"gfx/gui.png",NULL,{112,16,16,16},__("Use the level editor for more than 2 hours.")},
{"constructor2",__("The creator"),"gfx/gui.png",NULL,{112,16,16,16},__("Use the level editor for more than 24 hours.")},
+ {"create1",__("Look, cute level!"),"gfx/gui.png",NULL,{112,16,16,16},__("Created your first level.")},
+ {"create50",__("The level museum"),"gfx/gui.png",NULL,{112,16,16,16},__("Created 50 levels.")},
+
+ {"frog",__("Frog"),"themes/Cloudscape/player.png",NULL,{0,0,23,40},__("Jump for 1000 times.")},
+
+ {"die1",__("Be careful!"),"themes/Cloudscape/deathright.png",NULL,{0,14,23,40},__("The first death.")},
+ {"die50",__("It doesn't matter..."),"themes/Cloudscape/deathright.png",NULL,{0,14,23,40},__("Died for 50 times.")},
+ {"die1000",__("Expert of trial and error"),"themes/Cloudscape/deathright.png",NULL,{0,14,23,40},__("Died for 1000 times.")},
+
+ {"doubleKill",__("Double kill"),"themes/Cloudscape/deathright.png",NULL,{0,14,23,40},__("Make both player and shadow die.")},
+
//test only
{"programmer",__("Programmer"),"gfx/gui.png",NULL,{112,16,16,16},__("Played the development version of Me and My Shadow.")},
//end of achievements
{NULL,NULL,NULL,NULL,{0,0,0,0},NULL}
};
static map<string,AchievementInfo*> avaliableAchievements;
//================================================================
StatisticsManager::StatisticsManager(){
bmDropShadow=NULL;
bmAchievement=NULL;
startTime=time(NULL);
clear();
}
StatisticsManager::~StatisticsManager(){
if(bmAchievement){
SDL_FreeSurface(bmAchievement);
bmAchievement=NULL;
}
}
void StatisticsManager::clear(){
playerTravelingDistance=shadowTravelingDistance=0.0f;
playerJumps=shadowJumps
=playerDies=shadowDies
=completedLevels=silverLevels=goldLevels
=recordTimes=switchTimes=swapTimes
=playTime=levelEditTime
=createdLevels=0;
achievements.clear();
queuedAchievements.clear();
achievementTime=0;
currentAchievement=0;
if(bmAchievement){
SDL_FreeSurface(bmAchievement);
bmAchievement=NULL;
}
}
#define LOAD_STATS(var,func) { \
vector<string> &v=node.attributes[ #var ]; \
if(!v.empty() && !v[0].empty()) \
var=func(v[0].c_str()); \
}
void StatisticsManager::loadFile(const std::string& fileName){
clear();
ifstream file(fileName.c_str());
if(!file) return;
TreeStorageNode node;
POASerializer serializer;
if(!serializer.readNode(file,&node,true)) return;
//load statistics
LOAD_STATS(playerTravelingDistance,atof);
LOAD_STATS(shadowTravelingDistance,atof);
LOAD_STATS(playerJumps,atoi);
LOAD_STATS(shadowJumps,atoi);
LOAD_STATS(playerDies,atoi);
LOAD_STATS(shadowDies,atoi);
LOAD_STATS(recordTimes,atoi);
LOAD_STATS(switchTimes,atoi);
LOAD_STATS(swapTimes,atoi);
LOAD_STATS(playTime,atoi);
LOAD_STATS(levelEditTime,atoi);
LOAD_STATS(createdLevels,atoi);
//load achievements.
{
vector<string> &v=node.attributes["achievements"];
for(unsigned int i=0;i<v.size();i++){
map<string,AchievementInfo*>::iterator it=avaliableAchievements.find(v[i]);
if(it!=avaliableAchievements.end()){
achievements[it->first]=it->second;
}
}
}
}
//Call when level edit is start
void StatisticsManager::startLevelEdit(){
levelEditStartTime=time(NULL);
}
//Call when level edit is end
void StatisticsManager::endLevelEdit(){
levelEditTime+=time(NULL)-levelEditStartTime;
}
//update in-game time
void StatisticsManager::updatePlayTime(){
time_t endTime=time(NULL);
playTime+=endTime-startTime;
startTime=endTime;
}
#define SAVE_STATS(var,pattern) { \
sprintf(s,pattern,var); \
node.attributes[ #var ].push_back(s); \
}
void StatisticsManager::saveFile(const std::string& fileName){
char s[64];
//update in-game time
updatePlayTime();
ofstream file(fileName.c_str());
if(!file) return;
TreeStorageNode node;
//save statistics
SAVE_STATS(playerTravelingDistance,"%.2f");
SAVE_STATS(shadowTravelingDistance,"%.2f");
SAVE_STATS(playerJumps,"%d");
SAVE_STATS(shadowJumps,"%d");
SAVE_STATS(playerDies,"%d");
SAVE_STATS(shadowDies,"%d");
SAVE_STATS(recordTimes,"%d");
SAVE_STATS(switchTimes,"%d");
SAVE_STATS(swapTimes,"%d");
SAVE_STATS(playTime,"%d");
SAVE_STATS(levelEditTime,"%d");
SAVE_STATS(createdLevels,"%d");
//save achievements.
{
vector<string>& v=node.attributes["achievements"];
for(map<string,AchievementInfo*>::iterator it=achievements.begin();it!=achievements.end();++it){
v.push_back(it->first);
}
}
POASerializer serializer;
serializer.writeNode(&node,file,true,true);
}
void StatisticsManager::loadPicture(){
//Load drop shadow picture
bmDropShadow=loadImage(getDataPath()+"gfx/dropshadow.png");
}
void StatisticsManager::registerAchievements(){
if(!avaliableAchievements.empty()) return;
for(int i=0;achievementList[i].id!=NULL;i++){
avaliableAchievements[achievementList[i].id]=&achievementList[i];
if(achievementList[i].imageFile!=NULL){
achievementList[i].imageSurface=loadImage(getDataPath()+achievementList[i].imageFile);
}
}
}
void StatisticsManager::render(){
//debug
if(achievementTime==0){
if(SDL_GetKeyState(NULL)[SDLK_1]) newAchievement("hello",false);
if(SDL_GetKeyState(NULL)[SDLK_2]) newAchievement("123",false);
}
if(achievementTime==0 && bmAchievement==NULL && currentAchievement<(int)queuedAchievements.size()){
//create surface
bmAchievement=createAchievementSurface(queuedAchievements[currentAchievement++]);
//check if queue is empty
if(currentAchievement>=(int)queuedAchievements.size()){
queuedAchievements.clear();
currentAchievement=0;
}
//play a sound
if(getSettings()->getBoolValue("sound")){
Mix_PlayChannel(-1,achievementSound,0);
}
}
//check if we need to display achievements
if(bmAchievement){
achievementTime++;
if(achievementTime<=0){
return;
}else if(achievementTime<=5){
drawAchievement(achievementTime);
}else if(achievementTime<=achievementDisplayTime-5){
drawAchievement(5);
}else if(achievementTime<achievementDisplayTime){
drawAchievement(achievementDisplayTime-achievementTime);
}else if(achievementTime>=achievementIntervalTime){
if(bmAchievement){
SDL_FreeSurface(bmAchievement);
bmAchievement=NULL;
}
achievementTime=0;
}
}
}
void StatisticsManager::newAchievement(const std::string& id,bool save){
//check avaliable achievements
map<string,AchievementInfo*>::iterator it=avaliableAchievements.find(id);
if(it==avaliableAchievements.end()) return;
//check if already have this achievement
if(save){
map<string,AchievementInfo*>::iterator it2=achievements.find(id);
if(it2!=achievements.end()) return;
achievements[id]=it->second;
}
//add it to queue
queuedAchievements.push_back(it->second);
}
SDL_Surface* StatisticsManager::createAchievementSurface(AchievementInfo* info,SDL_Surface* surface,SDL_Rect* rect,bool showTip){
if(info==NULL || info->id==NULL) return NULL;
//prepare text
SDL_Surface *title0=NULL,*title1=NULL;
vector<SDL_Surface*> descSurfaces;
SDL_Color fg={0,0,0};
int fontHeight=TTF_FontLineSkip(fontText);
if(showTip) title0=TTF_RenderUTF8_Blended(fontText,_("New achievement:"),fg);
title1=TTF_RenderUTF8_Blended(fontGUISmall,_(info->name),fg);
if(info->description!=NULL){
string description=_(info->description);
string::size_type lps=0,lpe;
for(;;){
lpe=description.find('\n',lps);
if(lpe==string::npos){
descSurfaces.push_back(TTF_RenderUTF8_Blended(fontText,(description.substr(lps)+' ').c_str(),fg));
break;
}else{
descSurfaces.push_back(TTF_RenderUTF8_Blended(fontText,(description.substr(lps,lpe-lps)+' ').c_str(),fg));
lps=lpe+1;
}
}
}
//calculate the size
int w=0,h=0,w1=8,h1=0;
if(title0!=NULL){
if(title0->w>w) w=title0->w;
h1+=title0->h;
}
if(title1!=NULL){
if(title1->w>w) w=title1->w;
h1+=title1->h;
}
if(info->imageSurface!=NULL){
w1+=info->r.w+8;
w+=info->r.w+8;
if(info->r.h>h1) h1=info->r.h;
}
h=h1+8;
for(unsigned int i=0;i<descSurfaces.size();i++){
if(descSurfaces[i]!=NULL){
if(descSurfaces[i]->w>w) w=descSurfaces[i]->w;
}
}
h+=descSurfaces.size()*fontHeight;
w+=16;
h+=16;
//check if size is specified
int left=0,top=0;
if(rect!=NULL){
if(surface!=NULL){
left=rect->x;
top=rect->y;
}
if(rect->w>0) w=rect->w;
else rect->w=w;
rect->h=h;
}
//create surface if necessary
if(surface==NULL){
surface=SDL_CreateRGBSurface(SDL_HWSURFACE,w,h,
screen->format->BitsPerPixel,screen->format->Rmask,screen->format->Gmask,screen->format->Bmask,0);
}
//draw background
drawGUIBox(left,top,w,h,surface,0xFFFFFFFFU);
//draw picture
if(info->imageSurface!=NULL){
SDL_Rect r={left+8,top+8+(h1-info->r.h)/2,0,0};
SDL_BlitSurface(info->imageSurface,&info->r,surface,&r);
}
//draw text
h=8;
if(title0!=NULL){
SDL_Rect r={left+w1,top+h,0,0};
SDL_BlitSurface(title0,NULL,surface,&r);
h+=title0->h;
}
if(title1!=NULL){
SDL_Rect r={left+w1,top+h,0,0};
SDL_BlitSurface(title1,NULL,surface,&r);
}
h=h1+16;
for(unsigned int i=0;i<descSurfaces.size();i++){
if(descSurfaces[i]!=NULL){
SDL_Rect r={left+8,top+h+i*fontHeight,0,0};
SDL_BlitSurface(descSurfaces[i],NULL,surface,&r);
}
}
//clean up
if(title0) SDL_FreeSurface(title0);
if(title1) SDL_FreeSurface(title1);
for(unsigned int i=0;i<descSurfaces.size();i++){
if(descSurfaces[i]!=NULL){
SDL_FreeSurface(descSurfaces[i]);
}
}
//over
return surface;
}
void StatisticsManager::drawAchievement(int alpha){
if(bmAchievement==NULL) return;
if(alpha<=0) return;
if(alpha>5) alpha=5;
SDL_Rect r={screen->w-32-bmAchievement->w,32,
bmAchievement->w,bmAchievement->h};
//draw the surface
SDL_SetAlpha(bmAchievement,SDL_SRCALPHA,alpha*40);
SDL_BlitSurface(bmAchievement,NULL,screen,&r);
//draw drop shadow - corner
{
int w1=r.w/2,w2=r.w-w1,h1=r.h/2,h2=r.h-h1;
if(w1>16) w1=16;
if(w2>16) w2=16;
if(h1>16) h1=16;
if(h2>16) h2=16;
int x=(5-alpha)*64;
//top-left
SDL_Rect r1={x,0,w1+16,h1+16},r2={r.x-16,r.y-16,0,0};
SDL_BlitSurface(bmDropShadow,&r1,screen,&r2);
//top-right
r1.x=x+48-w2;r1.w=w2+16;r2.x=r.x+r.w-w2;
SDL_BlitSurface(bmDropShadow,&r1,screen,&r2);
//bottom-right
r1.y=48-h2;r1.h=h2+16;r2.y=r.y+r.h-h2;
SDL_BlitSurface(bmDropShadow,&r1,screen,&r2);
//bottom-left
r1.x=x;r1.w=w1+16;r2.x=r.x-16;
SDL_BlitSurface(bmDropShadow,&r1,screen,&r2);
}
//draw drop shadow - border
int i=r.w-32;
while(i>0){
int ii=i>128?128:i;
//top
SDL_Rect r1={0,256-alpha*16,ii,16},r2={r.x+r.w-16-i,r.y-16,0,0};
SDL_BlitSurface(bmDropShadow,&r1,screen,&r2);
//bottom
r1.x=128;r2.y=r.y+r.h;
SDL_BlitSurface(bmDropShadow,&r1,screen,&r2);
i-=ii;
}
i=r.h-32;
while(i>0){
int ii=i>128?128:i;
//top
SDL_Rect r1={512-alpha*16,0,16,ii},r2={r.x-16,r.y+r.h-16-i,0,0};
SDL_BlitSurface(bmDropShadow,&r1,screen,&r2);
//bottom
r1.y=128;r2.x=r.x+r.w;
SDL_BlitSurface(bmDropShadow,&r1,screen,&r2);
i-=ii;
}
}
void StatisticsManager::reloadCompletedLevelsAndAchievements(){
completedLevels=silverLevels=goldLevels=0;
LevelPackManager *lpm=getLevelPackManager();
vector<string> v=lpm->enumLevelPacks();
bool tutorial=false,tutorialGold=false;
for(unsigned int i=0;i<v.size();i++){
string& s=v[i];
LevelPack *levels=lpm->getLevelPack(s);
levels->loadProgress(getUserPath(USER_DATA)+"progress/"+s+".progress");
bool b=false;
if(s=="tutorial"){
b=tutorial=tutorialGold=true;
}
for(int n=0,m=levels->getLevelCount();n<m;n++){
LevelPack::Level *lv=levels->getLevel(n);
int medal=lv->won;
if(medal){
if(lv->targetTime<0 || lv->time<=lv->targetTime)
medal++;
if(lv->targetRecordings<0 || lv->recordings<=lv->targetRecordings)
medal++;
completedLevels++;
if(medal==2) silverLevels++;
if(medal==3) goldLevels++;
if(medal!=3 && b) tutorialGold=false;
}else if(b){
tutorial=tutorialGold=false;
}
}
}
//upadte achievements
updateLevelAchievements();
updateTutorialAchievementsInternal((tutorial?1:0)|(tutorialGold?2:0));
}
void StatisticsManager::reloadOtherAchievements(){
+ int i;
+
if(playTime>=7200) newAchievement("addicted");
if(playTime>=86400) newAchievement("loyalFan");
if(levelEditTime>=7200) newAchievement("constructor");
if(levelEditTime>=86400) newAchievement("constructor2");
+ if(createdLevels>=1) newAchievement("create1");
+ if(createdLevels>=50) newAchievement("create50");
+
+ i=playerJumps+shadowJumps;
+ if(i>=1000) newAchievement("frog");
+
+ i=playerDies+shadowDies;
+ if(i>=1) newAchievement("die1");
+ if(i>=50) newAchievement("die50");
+ if(i>=1000) newAchievement("die1000");
+
if(version.find("Development")!=string::npos) newAchievement("programmer");
}
//Update level specified achievements.
//Make sure the completed level count is correct.
void StatisticsManager::updateLevelAchievements(){
if(completedLevels>=1) newAchievement("newbie");
if(goldLevels>=1) newAchievement("goodjob");
if(completedLevels>=50) newAchievement("experienced");
if(goldLevels>=50) newAchievement("expert");
}
//Update tutorial specified achievements.
//Make sure the level progress of tutorial is correct.
void StatisticsManager::updateTutorialAchievements(){
//find tutorial level pack
LevelPackManager *lpm=getLevelPackManager();
LevelPack *levels=lpm->getLevelPack("tutorial");
if(levels==NULL) return;
bool tutorial=true,tutorialGold=true;
for(int n=0,m=levels->getLevelCount();n<m;n++){
LevelPack::Level *lv=levels->getLevel(n);
int medal=lv->won;
if(medal){
if(lv->targetTime<0 || lv->time<=lv->targetTime)
medal++;
if(lv->targetRecordings<0 || lv->recordings<=lv->targetRecordings)
medal++;
if(medal!=3) tutorialGold=false;
}else{
tutorial=tutorialGold=false;
break;
}
}
//upadte achievements
updateTutorialAchievementsInternal((tutorial?1:0)|(tutorialGold?2:0));
}
//internal function
//flags: a bit-field value indicates which achievements we have.
void StatisticsManager::updateTutorialAchievementsInternal(int flags){
if(flags&1) newAchievement("tutorial");
if(flags&2) newAchievement("tutorialGold");
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sat, May 16, 10:27 PM (1 d, 17 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
64193
Default Alt Text
(127 KB)
Attached To
Mode
R79 meandmyshadow
Attached
Detach File
Event Timeline