Page MenuHomePhabricator (Chris)

No OneTemporary

Authored By
Unknown
Size
127 KB
Referenced Files
None
Subscribers
None
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

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)

Event Timeline