Page MenuHomePhabricator (Chris)

No OneTemporary

Authored By
Unknown
Size
106 KB
Referenced Files
None
Subscribers
None
diff --git a/data/locale/zh_CN.po b/data/locale/zh_CN.po
index 1bae252..dc07a4d 100644
--- a/data/locale/zh_CN.po
+++ b/data/locale/zh_CN.po
@@ -1,702 +1,735 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: Me and my shadow\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2012-04-01 17:56+0300\n"
-"PO-Revision-Date: 2012-04-05 20:05+0800\n"
+"POT-Creation-Date: 2012-04-07 14:36+0800\n"
+"PO-Revision-Date: 2012-04-07 14:37+0800\n"
"Last-Translator: acme_pjz <acme_pjz@hotmail.com>\n"
"Language-Team: \n"
-"Language: \n"
"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=utf-8\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-SearchPath-0: F:\\Projects\\meandmyshadow\\src\n"
-#: src/Addons.cpp:40
-#: src/TitleMenu.cpp:46
+#: F:\Projects\meandmyshadow\src/Addons.cpp:40
msgid "Addons"
msgstr "附加组件"
-#: src/Addons.cpp:59
+#: F:\Projects\meandmyshadow\src/Addons.cpp:59
msgid "Unable to initialze addon menu:"
msgstr "不能初始化附加组件菜单:"
-#: src/Addons.cpp:67
-#: src/Addons.cpp:103
-#: src/LevelSelect.cpp:223
+#: F:\Projects\meandmyshadow\src/Addons.cpp:67
+#: F:\Projects\meandmyshadow\src/Addons.cpp:103
msgid "Back"
msgstr "后退"
-#: src/Addons.cpp:76
+#: F:\Projects\meandmyshadow\src/Addons.cpp:76
msgid "Levels"
msgstr "关卡列表"
-#: src/Addons.cpp:84
+#: F:\Projects\meandmyshadow\src/Addons.cpp:84
msgid "Level Packs"
msgstr "关卡包"
-#: src/Addons.cpp:88
+#: F:\Projects\meandmyshadow\src/Addons.cpp:88
msgid "Themes"
msgstr "主题"
-#: src/Addons.cpp:107
-#: src/Addons.cpp:589
+#: F:\Projects\meandmyshadow\src/Addons.cpp:107
+#: F:\Projects\meandmyshadow\src/Addons.cpp:589
msgid "Install"
msgstr "安装"
-#: src/Addons.cpp:111
+#: F:\Projects\meandmyshadow\src/Addons.cpp:111
msgid "Update"
msgstr "升级"
-#: src/Addons.cpp:415
-#: src/Addons.cpp:432
-#: src/Addons.cpp:449
-#: src/Addons.cpp:471
-#: src/Addons.cpp:485
-#: src/Addons.cpp:499
+#: F:\Projects\meandmyshadow\src/Addons.cpp:415
+#: F:\Projects\meandmyshadow\src/Addons.cpp:432
+#: F:\Projects\meandmyshadow\src/Addons.cpp:449
+#: F:\Projects\meandmyshadow\src/Addons.cpp:471
+#: F:\Projects\meandmyshadow\src/Addons.cpp:485
+#: F:\Projects\meandmyshadow\src/Addons.cpp:499
msgid "ERROR: Unable to download addon!"
msgstr "错误:无法下载附加组件"
-#: src/Addons.cpp:415
-#: src/Addons.cpp:432
-#: src/Addons.cpp:449
-#: src/Addons.cpp:471
-#: src/Addons.cpp:485
-#: src/Addons.cpp:499
+#: F:\Projects\meandmyshadow\src/Addons.cpp:415
+#: F:\Projects\meandmyshadow\src/Addons.cpp:432
+#: F:\Projects\meandmyshadow\src/Addons.cpp:449
+#: F:\Projects\meandmyshadow\src/Addons.cpp:471
+#: F:\Projects\meandmyshadow\src/Addons.cpp:485
+#: F:\Projects\meandmyshadow\src/Addons.cpp:499
msgid "ERROR:"
msgstr "错误:"
-#: src/Addons.cpp:584
+#: F:\Projects\meandmyshadow\src/Addons.cpp:584
msgid "Uninstall"
msgstr "卸载"
-#: src/Functions.cpp:658
-#: src/Functions.cpp:685
-#: src/Functions.cpp:1040
-#: src/InputManager.cpp:195
-#: src/LevelEditor.cpp:749
-#: src/LevelEditor.cpp:1361
-#: src/LevelEditor.cpp:1418
-#: src/LevelEditor.cpp:1481
-#: src/LevelEditor.cpp:1560
-#: src/LevelEditor.cpp:1665
-#: src/LevelEditor.cpp:1725
-#: src/LevelEditSelect.cpp:176
-#: src/LevelEditSelect.cpp:216
-#: src/LevelEditSelect.cpp:264
+#: F:\Projects\meandmyshadow\src/Functions.cpp:313
+#: F:\Projects\meandmyshadow\src/Functions.cpp:314
+msgid "knewave"
+msgstr "droidsans_final_fixed"
+
+#: F:\Projects\meandmyshadow\src/Functions.cpp:318
+msgid "Blokletters-Viltstift"
+msgstr "droidsans_final_fixed"
+
+#: F:\Projects\meandmyshadow\src/Functions.cpp:758
+#: F:\Projects\meandmyshadow\src/Functions.cpp:785
+#: F:\Projects\meandmyshadow\src/Functions.cpp:1139
+#: F:\Projects\meandmyshadow\src/InputManager.cpp:195
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:753
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1365
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1422
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1485
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1564
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1669
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1729
+#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:141
+#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:181
+#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:229
msgid "OK"
msgstr "确定"
-#: src/Functions.cpp:659
-#: src/Functions.cpp:671
-#: src/Functions.cpp:681
-#: src/Functions.cpp:1044
-#: src/LevelEditor.cpp:753
-#: src/LevelEditor.cpp:1365
-#: src/LevelEditor.cpp:1422
-#: src/LevelEditor.cpp:1485
-#: src/LevelEditor.cpp:1564
-#: src/LevelEditor.cpp:1669
-#: src/LevelEditor.cpp:1729
-#: src/LevelEditSelect.cpp:180
-#: src/LevelEditSelect.cpp:220
-#: src/LevelEditSelect.cpp:268
-#: src/TitleMenu.cpp:284
+#: F:\Projects\meandmyshadow\src/Functions.cpp:759
+#: F:\Projects\meandmyshadow\src/Functions.cpp:771
+#: F:\Projects\meandmyshadow\src/Functions.cpp:781
+#: F:\Projects\meandmyshadow\src/Functions.cpp:1143
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:757
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1369
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1426
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1489
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1568
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1673
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1733
+#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:145
+#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:185
+#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:233
msgid "Cancel"
msgstr "取消"
-#: src/Functions.cpp:663
+#: F:\Projects\meandmyshadow\src/Functions.cpp:763
msgid "Abort"
msgstr "终止"
-#: src/Functions.cpp:664
-#: src/Functions.cpp:680
+#: F:\Projects\meandmyshadow\src/Functions.cpp:764
+#: F:\Projects\meandmyshadow\src/Functions.cpp:780
msgid "Retry"
msgstr "重试"
-#: src/Functions.cpp:665
+#: F:\Projects\meandmyshadow\src/Functions.cpp:765
msgid "Ignore"
msgstr "忽略"
-#: src/Functions.cpp:669
-#: src/Functions.cpp:675
+#: F:\Projects\meandmyshadow\src/Functions.cpp:769
+#: F:\Projects\meandmyshadow\src/Functions.cpp:775
msgid "Yes"
msgstr "是"
-#: src/Functions.cpp:670
-#: src/Functions.cpp:676
+#: F:\Projects\meandmyshadow\src/Functions.cpp:770
+#: F:\Projects\meandmyshadow\src/Functions.cpp:776
msgid "No"
msgstr "否"
-#: src/Functions.cpp:808
+#: F:\Projects\meandmyshadow\src/Functions.cpp:907
#, c-format
msgid ""
"%s already exists.\n"
"Do you want to overwrite it?"
msgstr ""
"%s 已经存在。\n"
"你是否想要覆盖它?"
-#: src/Functions.cpp:808
+#: F:\Projects\meandmyshadow\src/Functions.cpp:907
msgid "Overwrite Prompt"
msgstr "文件覆盖提示"
-#: src/Functions.cpp:829
+#: F:\Projects\meandmyshadow\src/Functions.cpp:928
+#: F:\Projects\meandmyshadow\src/Functions.cpp:946
#, c-format
msgid "Can't open file %s."
msgstr "不能打开文件 %s。"
-#: src/Functions.cpp:829
-#: src/Functions.cpp:847
-#: src/LevelSelect.cpp:214
+#: F:\Projects\meandmyshadow\src/Functions.cpp:928
+#: F:\Projects\meandmyshadow\src/Functions.cpp:946
msgid "Error"
msgstr "错误"
-#: src/Functions.cpp:847
-#, c-format
-msgid "Can't open file %d."
-msgstr "不能打开文件 %d。"
-
-#: src/Functions.cpp:981
+#: F:\Projects\meandmyshadow\src/Functions.cpp:1080
msgid "Save File"
msgstr "保存文件"
-#: src/Functions.cpp:981
+#: F:\Projects\meandmyshadow\src/Functions.cpp:1080
msgid "Load File"
msgstr "打开文件"
-#: src/Functions.cpp:985
+#: F:\Projects\meandmyshadow\src/Functions.cpp:1084
msgid "Search In"
msgstr "查找范围"
-#: src/Functions.cpp:995
+#: F:\Projects\meandmyshadow\src/Functions.cpp:1094
msgid "File Name"
msgstr "文件名"
-#: src/Game.cpp:212
-#: src/Game.cpp:758
+#: F:\Projects\meandmyshadow\src/Game.cpp:214
+#: F:\Projects\meandmyshadow\src/Game.cpp:787
#, c-format
msgid "Level %d %s"
msgstr "第 %d 关 %s"
-#: src/Game.cpp:694
+#: F:\Projects\meandmyshadow\src/Game.cpp:635
+#, c-format
+msgid "Press %s key to save the game."
+msgstr "按 %s 键来保存游戏。"
+
+#: F:\Projects\meandmyshadow\src/Game.cpp:640
+#, c-format
+msgid "Press %s key to swap the position of player and shadow."
+msgstr "按 %s 键交换你和阴影的位置。"
+
+#: F:\Projects\meandmyshadow\src/Game.cpp:645
+#, c-format
+msgid "Press %s key to activate the switch."
+msgstr "按 %s 键来激活开关。"
+
+#: F:\Projects\meandmyshadow\src/Game.cpp:650
+#, c-format
+msgid "Press %s key to teleport."
+msgstr "按 %s 键传送。"
+
+#: F:\Projects\meandmyshadow\src/Game.cpp:691
+#, 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:704
+#, c-format
+msgid "Press %s to restart current level."
+msgstr "按 %s 键重新开始游戏。"
+
+#: F:\Projects\meandmyshadow\src/Game.cpp:719
msgid "Your shadow has died."
-msgstr "你的阴影挂掉了。"
+msgstr "你的阴影死掉了。"
-#: src/Game.cpp:714
+#: F:\Projects\meandmyshadow\src/Game.cpp:739
#, c-format
msgid "%d recordings"
msgstr "记录数 %d"
-#: src/Game.cpp:753
+#: F:\Projects\meandmyshadow\src/Game.cpp:779
msgid "You've finished:"
msgstr "恭喜你完成了:"
-#: src/Game.cpp:905
+#: F:\Projects\meandmyshadow\src/Game.cpp:939
#, c-format
msgid "Time: %-.2fs"
msgstr "时间: %-.2f秒"
-#: src/Game.cpp:908
+#: F:\Projects\meandmyshadow\src/Game.cpp:945
#, c-format
msgid "Best time: %-.2fs"
msgstr "最佳时间: %-.2f秒"
-#: src/Game.cpp:912
+#: F:\Projects\meandmyshadow\src/Game.cpp:952
#, c-format
msgid "Target time: %-.2fs"
msgstr "目标时间: %-.2f秒"
-#: src/Game.cpp:917
+#: F:\Projects\meandmyshadow\src/Game.cpp:959
#, c-format
msgid "Recordings: %d"
msgstr "记录次数: %d"
-#: src/Game.cpp:920
+#: F:\Projects\meandmyshadow\src/Game.cpp:964
#, c-format
msgid "Best recordings: %d"
msgstr "最佳记录次数: %d"
-#: src/Game.cpp:924
+#: F:\Projects\meandmyshadow\src/Game.cpp:970
#, c-format
msgid "Target recordings: %d"
msgstr "目标记录次数: %d"
-#: src/Game.cpp:929
+#: F:\Projects\meandmyshadow\src/Game.cpp:977
#, c-format
msgid "You earned the %s medal"
msgstr "你拿到了%s"
-#: src/Game.cpp:929
+#: F:\Projects\meandmyshadow\src/Game.cpp:977
msgid "GOLD"
msgstr "金牌"
-#: src/Game.cpp:929
+#: F:\Projects\meandmyshadow\src/Game.cpp:977
msgid "SILVER"
msgstr "银牌"
-#: src/Game.cpp:929
+#: F:\Projects\meandmyshadow\src/Game.cpp:977
msgid "BRONZE"
msgstr "铜牌"
-#: src/Game.cpp:939
+#: F:\Projects\meandmyshadow\src/Game.cpp:988
msgid "Menu"
msgstr "菜单"
-#: src/Game.cpp:944
+#: F:\Projects\meandmyshadow\src/Game.cpp:994
msgid "Restart"
msgstr "重新开始"
-#: src/Game.cpp:949
+#: F:\Projects\meandmyshadow\src/Game.cpp:1000
msgid "Next"
msgstr "下一关"
-#: src/Game.cpp:976
+#: F:\Projects\meandmyshadow\src/Game.cpp:1027
msgid "Game replay is done."
msgstr "游戏重放已经完成。"
-#: src/Game.cpp:976
+#: F:\Projects\meandmyshadow\src/Game.cpp:1027
msgid "Game Replay"
msgstr "游戏重放"
-#: src/Game.cpp:1105
-#: src/Game.cpp:1107
+#: F:\Projects\meandmyshadow\src/Game.cpp:1156
+#: F:\Projects\meandmyshadow\src/Game.cpp:1158
msgid "Congratulations"
msgstr "恭喜你"
-#: src/Game.cpp:1107
+#: F:\Projects\meandmyshadow\src/Game.cpp:1158
msgid "You have finished the levelpack!"
msgstr "你已经完成了整个关卡包!"
-#: src/InputManager.cpp:162
-#: src/TitleMenu.cpp:273
+#: F:\Projects\meandmyshadow\src/InputManager.cpp:162
msgid "Config Keys"
msgstr "设置按键"
-#: src/InputManager.cpp:165
+#: F:\Projects\meandmyshadow\src/InputManager.cpp:165
msgid "Select an item and press a key to config it."
msgstr "选择一个项目,然后按键进行设置。"
-#: src/InputManager.cpp:178
+#: F:\Projects\meandmyshadow\src/InputManager.cpp:178
msgid "Primary key"
msgstr "主按键"
-#: src/InputManager.cpp:179
+#: F:\Projects\meandmyshadow\src/InputManager.cpp:179
msgid "Alternative key"
msgstr "辅助按键"
-#: src/InputManager.cpp:185
+#: F:\Projects\meandmyshadow\src/InputManager.cpp:185
msgid "Unset the key"
msgstr "取消设置"
-#: src/InputManager.cpp:299
+#: F:\Projects\meandmyshadow\src/InputManager.cpp:299
msgid "(Not set)"
msgstr "(未设置)"
-#: src/LevelEditor.cpp:283
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:287
msgid "Are you sure you want to quit?"
msgstr "你确定要退出吗?"
-#: src/LevelEditor.cpp:283
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:287
msgid "Quit prompt"
msgstr "退出提示"
-#: src/LevelEditor.cpp:689
-#: src/LevelEditor.cpp:691
-#: src/LevelEditor.cpp:2311
-#: src/LevelEditor.cpp:2313
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:693
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:695
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2315
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2317
#, c-format
msgid "Level \"%s\" saved"
msgstr "关卡“%s”已保存"
-#: src/LevelEditor.cpp:689
-#: src/LevelEditor.cpp:691
-#: src/LevelEditor.cpp:2311
-#: src/LevelEditor.cpp:2313
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:693
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:695
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2315
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2317
msgid "Saved"
msgstr "已保存"
-#: src/LevelEditor.cpp:704
-#: src/LevelEditor.cpp:2429
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:708
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2433
msgid "Level settings"
msgstr "关卡设置"
-#: src/LevelEditor.cpp:708
-#: src/LevelEditSelect.cpp:155
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:712
+#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:120
msgid "Name:"
msgstr "名称:"
-#: src/LevelEditor.cpp:714
-#: src/TitleMenu.cpp:219
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:718
msgid "Theme:"
msgstr "主题:"
-#: src/LevelEditor.cpp:729
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:733
msgid "Target time (s):"
msgstr "目标时间(秒):"
-#: src/LevelEditor.cpp:740
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:744
msgid "Target recordings:"
msgstr "目标记录数:"
-#: src/LevelEditor.cpp:1308
-#: src/LevelEditor.cpp:1524
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1312
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1528
msgid "Defined"
msgstr "已设置"
-#: src/LevelEditor.cpp:1311
-#: src/LevelEditor.cpp:1527
-#: src/LevelEditor.cpp:1608
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1315
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1531
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1612
msgid "None"
msgstr "无"
-#: src/LevelEditor.cpp:1318
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1322
msgid "Moving block"
msgstr "移动砖块"
-#: src/LevelEditor.cpp:1321
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1325
msgid "Moving shadow block"
msgstr "移动阴影砖块"
-#: src/LevelEditor.cpp:1324
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1328
msgid "Moving spikes"
msgstr "移动的刺"
-#: src/LevelEditor.cpp:1331
-#: src/LevelEditor.cpp:1467
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1335
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1471
msgid "Enabled"
msgstr "启用"
-#: src/LevelEditor.cpp:1337
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1341
msgid "Loop"
msgstr "循环"
-#: src/LevelEditor.cpp:1343
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1347
msgid "Path"
msgstr "路径"
-#: src/LevelEditor.cpp:1402
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1406
msgid "Notification block"
msgstr "消息方块"
-#: src/LevelEditor.cpp:1405
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1409
msgid "Enter message here:"
msgstr "输入消息:"
-#: src/LevelEditor.cpp:1459
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1463
msgid "Shadow Conveyor belt"
msgstr "阴影传送带"
-#: src/LevelEditor.cpp:1461
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1465
msgid "Conveyor belt"
msgstr "传送带"
-#: src/LevelEditor.cpp:1473
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1477
msgid "Enter speed here:"
msgstr "输入速度:"
-#: src/LevelEditor.cpp:1531
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1535
msgid "Portal"
msgstr "传送门"
-#: src/LevelEditor.cpp:1534
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1538
msgid "Activate on touch"
msgstr "接触时传送"
-#: src/LevelEditor.cpp:1540
-#: src/LevelEditor.cpp:1644
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1544
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1648
msgid "Targets:"
msgstr "目标:"
-#: src/LevelEditor.cpp:1614
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1618
msgid "Button"
msgstr "按钮:"
-#: src/LevelEditor.cpp:1616
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1620
msgid "Switch"
msgstr "开关:"
-#: src/LevelEditor.cpp:1621
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1625
msgid "Behaviour:"
msgstr "行为:"
-#: src/LevelEditor.cpp:1627
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1631
msgid "On"
msgstr "开启"
-#: src/LevelEditor.cpp:1628
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1632
msgid "Off"
msgstr "关闭"
-#: src/LevelEditor.cpp:1629
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1633
msgid "Toggle"
msgstr "切换"
-#: src/LevelEditor.cpp:1705
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1709
msgid "Fragile"
msgstr "易碎砖块"
-#: src/LevelEditor.cpp:1708
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1712
msgid "State:"
msgstr "状态:"
-#: src/LevelEditor.cpp:1714
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1718
msgid "Complete"
msgstr "完整的"
-#: src/LevelEditor.cpp:1715
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1719
msgid "One step"
msgstr "踩了一次"
-#: src/LevelEditor.cpp:1716
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1720
msgid "Two steps"
msgstr "踩了两次"
-#: src/LevelEditor.cpp:1717
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:1721
msgid "Gone"
msgstr "已经破碎"
-#: src/LevelEditor.cpp:2414
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2418
msgid "Select"
msgstr "选择"
-#: src/LevelEditor.cpp:2417
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2421
msgid "Add"
msgstr "添加"
-#: src/LevelEditor.cpp:2420
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2424
msgid "Delete"
msgstr "删除"
-#: src/LevelEditor.cpp:2423
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2427
msgid "Configure"
msgstr "设置"
-#: src/LevelEditor.cpp:2426
-#: src/LevelPlaySelect.cpp:49
-#: src/TitleMenu.cpp:43
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2430
msgid "Play"
msgstr "开始游戏"
-#: src/LevelEditor.cpp:2432
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2436
msgid "Save level"
msgstr "保存关卡"
-#: src/LevelEditor.cpp:2435
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2439
msgid "Back to menu"
msgstr "回主菜单"
-#: src/LevelEditor.cpp:2481
+#: F:\Projects\meandmyshadow\src/LevelEditor.cpp:2485
#, c-format
msgid "Movespeed: %s"
msgstr "移动速度: %s"
-#: src/LevelEditSelect.cpp:41
-#: src/TitleMenu.cpp:45
+#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:41
msgid "Map Editor"
msgstr "地图编辑器"
-#: src/LevelEditSelect.cpp:49
+#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:49
msgid "New Levelpack"
msgstr "新建关卡包"
-#: src/LevelEditSelect.cpp:54
+#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:54
msgid "Pack Properties"
msgstr "关卡包属性"
-#: src/LevelEditSelect.cpp:59
+#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:59
msgid "Remove Pack"
msgstr "删除关卡包"
-#: src/LevelEditSelect.cpp:64
+#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:64
msgid "Move Map"
msgstr "移动地图"
-#: src/LevelEditSelect.cpp:70
+#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:70
msgid "Remove Map"
msgstr "删除地图"
-#: src/LevelEditSelect.cpp:76
+#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:76
msgid "Edit Map"
msgstr "编辑地图"
-#: src/LevelEditSelect.cpp:139
-#: src/LevelSelect.cpp:214
-#, c-format
-msgid ""
-"Can't load level pack:\n"
-"%s"
-msgstr ""
-"无法打开关卡包:\n"
-"%s"
-
-#: src/LevelEditSelect.cpp:152
+#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:117
msgid "Properties"
msgstr "属性"
-#: src/LevelEditSelect.cpp:162
+#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:127
msgid "Description:"
msgstr "描述:"
-#: src/LevelEditSelect.cpp:169
+#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:134
msgid "Congratulation text:"
msgstr "完成提示:"
-#: src/LevelEditSelect.cpp:204
-#: src/LevelEditSelect.cpp:360
+#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:169
+#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:329
msgid "Add level"
msgstr "增加关卡"
-#: src/LevelEditSelect.cpp:207
+#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:172
msgid "File name:"
msgstr "文件名:"
-#: src/LevelEditSelect.cpp:244
+#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:209
msgid "Move level"
msgstr "移动关卡"
-#: src/LevelEditSelect.cpp:247
+#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:212
msgid "Level: "
msgstr "关卡:"
-#: src/LevelEditSelect.cpp:251
+#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:216
msgid "MoveLevel"
msgstr "移动关卡"
-#: src/LevelEditSelect.cpp:257
+#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:222
msgid "Before"
msgstr "之前"
-#: src/LevelEditSelect.cpp:258
+#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:223
msgid "After"
msgstr "之后"
-#: src/LevelEditSelect.cpp:259
+#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:224
msgid "Swap"
msgstr "交换"
-#: src/LevelEditSelect.cpp:442
+#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:397
msgid "Are you sure?"
msgstr "你确定吗?"
-#: src/LevelEditSelect.cpp:442
+#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:397
msgid "Remove prompt"
msgstr "删除提示"
-#: src/LevelEditSelect.cpp:585
+#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:537
msgid "No file name given for the new level."
msgstr "没有给新关卡指定文件名。"
-#: src/LevelEditSelect.cpp:585
+#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:537
msgid "Missing file name"
msgstr "文件名未指定"
-#: src/LevelEditSelect.cpp:662
+#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:614
msgid "The entered level number isn't valid!"
msgstr "输入的关卡编号无效!"
-#: src/LevelEditSelect.cpp:662
+#: F:\Projects\meandmyshadow\src/LevelEditSelect.cpp:614
msgid "Illegal number"
msgstr "无效编号"
-#: src/LevelPlaySelect.cpp:43
+#: F:\Projects\meandmyshadow\src/LevelPlaySelect.cpp:43
msgid "Select Level"
msgstr "选择关卡"
-#: src/LevelPlaySelect.cpp:80
+#: F:\Projects\meandmyshadow\src/LevelPlaySelect.cpp:80
msgid "Choose a level"
msgstr "选择一个关卡"
-#: src/LevelPlaySelect.cpp:81
-#: src/LevelPlaySelect.cpp:215
-#: src/LevelPlaySelect.cpp:226
+#: F:\Projects\meandmyshadow\src/LevelPlaySelect.cpp:81
+#: F:\Projects\meandmyshadow\src/LevelPlaySelect.cpp:219
+#: F:\Projects\meandmyshadow\src/LevelPlaySelect.cpp:230
msgid "Time:"
msgstr "时间:"
-#: src/LevelPlaySelect.cpp:82
-#: src/LevelPlaySelect.cpp:224
-#: src/LevelPlaySelect.cpp:227
+#: F:\Projects\meandmyshadow\src/LevelPlaySelect.cpp:82
+#: F:\Projects\meandmyshadow\src/LevelPlaySelect.cpp:228
+#: F:\Projects\meandmyshadow\src/LevelPlaySelect.cpp:231
msgid "Recordings:"
msgstr "记录次数:"
-#: src/TitleMenu.cpp:44
+#: F:\Projects\meandmyshadow\src/TitleMenu.cpp:48
msgid "Options"
msgstr "选项"
-#: src/TitleMenu.cpp:47
+#: F:\Projects\meandmyshadow\src/TitleMenu.cpp:51
msgid "Exit"
msgstr "退出"
-#: src/TitleMenu.cpp:105
+#: F:\Projects\meandmyshadow\src/TitleMenu.cpp:109
msgid "Enable internet in order to install addons."
msgstr "启用网络访问,才能下载附加组件。"
-#: src/TitleMenu.cpp:105
+#: F:\Projects\meandmyshadow\src/TitleMenu.cpp:109
msgid "Internet disabled"
msgstr "网络已禁用"
-#: src/TitleMenu.cpp:178
+#: F:\Projects\meandmyshadow\src/TitleMenu.cpp:206
msgid "Settings"
msgstr "选项"
-#: src/TitleMenu.cpp:204
+#: F:\Projects\meandmyshadow\src/TitleMenu.cpp:234
msgid "Music"
msgstr "音乐"
-#: src/TitleMenu.cpp:209
+#: F:\Projects\meandmyshadow\src/TitleMenu.cpp:239
msgid "Sound"
msgstr "音效"
-#: src/TitleMenu.cpp:214
+#: F:\Projects\meandmyshadow\src/TitleMenu.cpp:244
msgid "Fullscreen"
msgstr "全屏幕"
-#: src/TitleMenu.cpp:252
+#: F:\Projects\meandmyshadow\src/TitleMenu.cpp:249
+msgid "Resolution:"
+msgstr "分辨率:"
+
+#: F:\Projects\meandmyshadow\src/TitleMenu.cpp:284
+msgid "Language:"
+msgstr "语言:"
+
+#: F:\Projects\meandmyshadow\src/TitleMenu.cpp:293
+msgid "Auto-Detect"
+msgstr "自动检测"
+
+#: F:\Projects\meandmyshadow\src/TitleMenu.cpp:354
msgid "Level themes"
msgstr "默认主题"
-#: src/TitleMenu.cpp:257
+#: F:\Projects\meandmyshadow\src/TitleMenu.cpp:359
msgid "Internet"
msgstr "网络"
-#: src/TitleMenu.cpp:263
+#: F:\Projects\meandmyshadow\src/TitleMenu.cpp:365
msgid "Internet proxy"
msgstr "网络代理"
-#: src/TitleMenu.cpp:279
+#: F:\Projects\meandmyshadow\src/TitleMenu.cpp:382
msgid "Clear Progress"
msgstr "清除进度"
-#: src/TitleMenu.cpp:289
+#: F:\Projects\meandmyshadow\src/TitleMenu.cpp:392
msgid "Save Changes"
msgstr "保存变更"
-#: src/TitleMenu.cpp:335
+#: F:\Projects\meandmyshadow\src/TitleMenu.cpp:458
msgid "Restart needed before the changes have effect."
msgstr "重新启动游戏才能使新的选项生效。"
-#: src/TitleMenu.cpp:335
+#: F:\Projects\meandmyshadow\src/TitleMenu.cpp:458
msgid "Restart needed"
msgstr "需要重新启动"
-#: src/TitleMenu.cpp:342
+#: F:\Projects\meandmyshadow\src/TitleMenu.cpp:465
msgid "Do you really want to reset level progress?"
msgstr "你确定要清除游戏进度吗?"
-#: src/TitleMenu.cpp:342
+#: F:\Projects\meandmyshadow\src/TitleMenu.cpp:465
msgid "Warning"
msgstr "警告"
-msgid "knewave"
-msgstr "droidsans_final_fixed"
-
-msgid "Blokletters-Viltstift"
-msgstr "droidsans_final_fixed"
+#~ msgid "Can't open file %d."
+#~ msgstr "不能打开文件 %d。"
+#~ msgid ""
+#~ "Can't load level pack:\n"
+#~ "%s"
+#~ msgstr ""
+#~ "无法打开关卡包:\n"
+#~ "%s"
diff --git a/src/Game.cpp b/src/Game.cpp
index e7635f9..76eb190 100644
--- a/src/Game.cpp
+++ b/src/Game.cpp
@@ -1,1195 +1,1195 @@
/****************************************************************************
** Copyright (C) 2011 Luka Horvat <redreaper132 at gmail.com>
** Copyright (C) 2011 Edward Lii <edward_iii at myway.com>
** Copyright (C) 2011 O. Bahri Gordebak <gordebak at gmail.com>
**
**
** This file may be used under the terms of the GNU General Public
** License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of
** this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
**
****************************************************************************/
#include "GameState.h"
#include "Globals.h"
#include "Functions.h"
#include "FileManager.h"
#include "GameObjects.h"
#include "ThemeManager.h"
#include "Objects.h"
#include "Game.h"
#include "TreeStorageNode.h"
#include "POASerializer.h"
#include "InputManager.h"
#include <fstream>
#include <iostream>
#include <sstream>
#include <vector>
#include <map>
#include <algorithm>
#include <locale>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "libs/tinyformat/tinyformat.h"
using namespace std;
const char* Game::blockName[TYPE_MAX]={"Block","PlayerStart","ShadowStart",
"Exit","ShadowBlock","Spikes",
"Checkpoint","Swap","Fragile",
"MovingBlock","MovingShadowBlock","MovingSpikes",
"Teleporter","Button","Switch",
"ConveyorBelt","ShadowConveyorBelt","NotificationBlock",
};
map<string,int> Game::blockNameMap;
string Game::recordFile;
Game::Game(bool loadLevel):isReset(false)
,currentLevelNode(NULL)
,customTheme(NULL)
,background(NULL)
,won(false)
,interlevel(false)
,gameTipIndex(0)
,time(0),timeSaved(0)
,recordings(0),recordingsSaved(0)
,shadowCam(false)
,player(this),shadow(this),objLastCheckPoint(NULL){
//Reserve the memory for the GameObject tips.
memset(bmTips,0,sizeof(bmTips));
action=loadImage(getDataPath()+"gfx/actions.png");
medals=loadImage(getDataPath()+"gfx/medals.png");
//Check if we should load record file.
if(!recordFile.empty()){
loadRecord(recordFile.c_str());
recordFile.clear();
return;
}
//If we should load the level then load it.
if(loadLevel){
this->loadLevel(levels->getLevelpackPath()+levels->getLevelFile());
levels->saveLevelProgress();
}
}
Game::~Game(){
//Simply call our destroy method.
destroy();
}
void Game::destroy(){
//Loop through the levelObjects and delete them.
for(unsigned int i=0;i<levelObjects.size();i++)
delete levelObjects[i];
//Done now clear the levelObjects vector.
levelObjects.clear();
//Clear the name and the editor data.
levelName.clear();
levelFile.clear();
editorData.clear();
//Loop through the tips.
for(int i=0;i<TYPE_MAX;i++){
//If it exist free the SDL_Surface.
if(bmTips[i])
SDL_FreeSurface(bmTips[i]);
}
memset(bmTips,0,sizeof(bmTips));
//Remove everything from the themeManager.
background=NULL;
if(customTheme)
objThemes.removeTheme();
customTheme=NULL;
//delete current level (if any)
if(currentLevelNode){
delete currentLevelNode;
currentLevelNode=NULL;
}
//Reset the time.
time=timeSaved=0;
recordings=recordingsSaved=0;
}
void Game::loadLevelFromNode(TreeStorageNode* obj,const string& fileName){
//Make sure there's nothing left from any previous levels.
destroy();
//set current level to loaded one.
currentLevelNode=obj;
//Temp var used for block locations.
SDL_Rect box;
//Set the level dimensions to the default, it will probably be changed by the editorData,
//but 800x600 is a fallback.
LEVEL_WIDTH=800;
LEVEL_HEIGHT=600;
//Load the additional data.
for(map<string,vector<string> >::iterator i=obj->attributes.begin();i!=obj->attributes.end();i++){
if(i->first=="size"){
//We found the size attribute.
if(i->second.size()>=2){
//Set the dimensions of the level.
LEVEL_WIDTH=atoi(i->second[0].c_str());
LEVEL_HEIGHT=atoi(i->second[1].c_str());
}
}else if(i->second.size()>0){
//Any other data will be put into the editorData.
editorData[i->first]=i->second[0];
}
}
//Get the theme.
{
//If a theme is configured then load it.
string theme=processFileName(getSettings()->getValue("theme"));
//Check if it isn't the default theme, because if it is it's already loaded.
if(fileNameFromPath(theme)!="Cloudscape") {
customTheme=objThemes.appendThemeFromFile(theme+"/theme.mnmstheme");
}
//Check if level themes are enabled.
if(getSettings()->getBoolValue("leveltheme")) {
string &s=editorData["theme"];
if(!s.empty()){
customTheme=objThemes.appendThemeFromFile(processFileName(theme)+"/theme.mnmstheme");
}
}
//Set the Appearance of the player and the shadow.
objThemes.getCharacter(false)->createInstance(&player.appearance);
objThemes.getCharacter(true)->createInstance(&shadow.appearance);
}
for(unsigned int i=0;i<obj->subNodes.size();i++){
TreeStorageNode* obj1=obj->subNodes[i];
if(obj1==NULL) continue;
if(obj1->name=="tile" && obj1->value.size()>=3){
int objectType=blockNameMap[obj1->value[0]];
box.x=atoi(obj1->value[1].c_str());
box.y=atoi(obj1->value[2].c_str());
map<string,string> obj;
for(map<string,vector<string> >::iterator i=obj1->attributes.begin();i!=obj1->attributes.end();i++){
if(i->second.size()>0) obj[i->first]=i->second[0];
}
levelObjects.push_back( new Block ( box.x, box.y, objectType, this) );
levelObjects.back()->setEditorData(obj);
}
}
//Set the levelName to the name of the current level.
levelName=editorData["name"];
levelFile=fileName;
//Some extra stuff only needed when not in the levelEditor.
if(stateID!=STATE_LEVEL_EDITOR){
//We create a text with the text "Level <levelno> <levelName>".
//It will be shown in the left bottom corner of the screen.
string s;
if (levels->getLevelCount()>1){
s=tfm::format(_("Level %d %s"),levels->getCurrentLevel()+1,editorData["name"]);
}
SDL_Color fg={0,0,0,0};
SDL_Color bg={255,255,255,0};
bmTips[0]=TTF_RenderUTF8_Shaded(fontText,s.c_str(),fg,bg);
if(bmTips[0])
SDL_SetAlpha(bmTips[0],SDL_SRCALPHA,160);
}
//Get the background
background=objThemes.getBackground();
if(background)
background->resetAnimation(true);
}
void Game::loadLevel(string fileName){
//Create a TreeStorageNode that will hold the loaded data.
TreeStorageNode *obj=new TreeStorageNode();
{
POASerializer objSerializer;
string s=fileName;
//Parse the file.
if(!objSerializer.loadNodeFromFile(s.c_str(),obj,true)){
cout<<"Can't load level file "<<s<<endl;
delete obj;
return;
}
}
//Now call another function.
loadLevelFromNode(obj,fileName);
}
void Game::saveRecord(const char* fileName){
//check if current level is NULL (which should be impossible)
if(currentLevelNode==NULL) return;
TreeStorageNode obj;
POASerializer objSerializer;
//put current level to the node.
currentLevelNode->name="map";
obj.subNodes.push_back(currentLevelNode);
//serialize the game record using RLE compression.
#define PUSH_BACK \
if(j>0){ \
if(j>1){ \
sprintf(c,"%d*%d",last,j); \
}else{ \
sprintf(c,"%d",last); \
} \
v.push_back(c); \
}
vector<string> &v=obj.attributes["record"];
vector<int> *record=player.getRecord();
char c[64];
int i,j=0,last;
for(i=0;i<(int)record->size();i++){
int currentKey=(*record)[i];
if(j==0 || currentKey!=last){
PUSH_BACK;
last=currentKey;
j=1;
}else{
j++;
}
}
PUSH_BACK;
#undef PUSH_BACK
#ifdef RECORD_FILE_DEBUG
//add record file debug data.
{
obj.attributes["recordKeyPressLog"].push_back(player.keyPressLog());
vector<SDL_Rect> &playerPosition=player.playerPosition();
string s;
char c[32];
sprintf(c,"%d\n",int(playerPosition.size()));
s=c;
for(unsigned int i=0;i<playerPosition.size();i++){
SDL_Rect& r=playerPosition[i];
sprintf(c,"%d %d\n",r.x,r.y);
s+=c;
}
obj.attributes["recordPlayerPosition"].push_back(s);
}
#endif
//save it
objSerializer.saveNodeToFile(fileName,&obj,true,true);
//remove current level from node to prevent delete it.
obj.subNodes.clear();
}
void Game::loadRecord(const char* fileName){
//Create a TreeStorageNode that will hold the loaded data.
TreeStorageNode obj;
{
POASerializer objSerializer;
string s=fileName;
//Parse the file.
if(!objSerializer.loadNodeFromFile(s.c_str(),&obj,true)){
cout<<"Can't load record file "<<s<<endl;
return;
}
}
//find the node named 'map'.
bool loaded=false;
for(unsigned int i=0;i<obj.subNodes.size();i++){
if(obj.subNodes[i]->name=="map"){
//load the level. (fileName=???)
loadLevelFromNode(obj.subNodes[i],"???");
//remove this node to prevent delete it.
obj.subNodes[i]=NULL;
//over
loaded=true;
break;
}
}
if(!loaded){
cout<<"ERROR: Can't find subnode named 'map' from record file"<<endl;
return;
}
//load the record.
{
vector<int> *record=player.getRecord();
record->clear();
vector<string> &v=obj.attributes["record"];
for(unsigned int i=0;i<v.size();i++){
string &s=v[i];
string::size_type pos=s.find_first_of('*');
if(pos==string::npos){
//1 item only.
int i=atoi(s.c_str());
record->push_back(i);
}else{
//contains many items.
int i=atoi(s.substr(0,pos).c_str());
int j=atoi(s.substr(pos+1).c_str());
for(;j>0;j--){
record->push_back(i);
}
}
}
}
#ifdef RECORD_FILE_DEBUG
//load the debug data
{
vector<string> &v=obj.attributes["recordPlayerPosition"];
vector<SDL_Rect> &playerPosition=player.playerPosition();
playerPosition.clear();
if(!v.empty()){
if(!v[0].empty()){
stringstream st(v[0]);
int m;
st>>m;
for(int i=0;i<m;i++){
SDL_Rect r;
st>>r.x>>r.y;
r.w=0;
r.h=0;
playerPosition.push_back(r);
}
}
}
}
#endif
//play the record.
//TODO: tell the level manager don't save the level progress.
player.playRecord();
shadow.playRecord(); //???
}
/////////////EVENT///////////////
void Game::handleEvents(){
//First of all let the player handle input.
player.handleInput(&shadow);
//Check for an SDL_QUIT event.
if(event.type==SDL_QUIT){
//We need to quit so enter STATE_EXIT.
setNextState(STATE_EXIT);
}
//Check for the escape key.
if(inputMgr.isKeyUpEvent(INPUTMGR_ESCAPE)){
//Escape means we go one level up, to the level select state.
setNextState(STATE_LEVEL_SELECT);
//Save the progress.
levels->saveLevelProgress();
//And change the music back to the menu music.
getMusicManager()->playMusic("menu");
}
//Check if 'r' is pressed.
if(inputMgr.isKeyDownEvent(INPUTMGR_RESTART)){
//Check if it isn't a replay.
if(!player.isPlayFromRecord()){
//Set reset true.
isReset=true;
}else if(interlevel){
//We can also reset during the inter level screen.
if(GUIObjectRoot){
delete GUIObjectRoot;
GUIObjectRoot=NULL;
}
isReset=true;
}
}
//Check for the next level buttons when in the interlevel popup.
if(inputMgr.isKeyDownEvent(INPUTMGR_SPACE) || (event.type==SDL_KEYDOWN && (event.key.keysym.sym==SDLK_RETURN || event.key.keysym.sym==SDLK_RCTRL))){
if(interlevel){
//The interlevel popup is shown so we need to delete it.
if(GUIObjectRoot){
delete GUIObjectRoot;
GUIObjectRoot=NULL;
}
//Now goto the next level.
gotoNextLevel();
}
}
//Check if tab is pressed.
if(inputMgr.isKeyDownEvent(INPUTMGR_TAB)){
shadowCam=!shadowCam;
}
}
/////////////////LOGIC///////////////////
void Game::logic(){
//Add one tick to the time.
time++;
//Let the player store his move, if recording.
player.shadowSetState();
//Let the player give his recording to the shadow, if configured.
player.shadowGiveState(&shadow);
//Let the player jump.
player.jump();
//Let him move.
player.move(levelObjects);
//And let the camera follow him.
if(!shadowCam){
player.setMyCamera();
}else{
shadow.setMyCamera();
}
//Now let the shadow decide his move, if he's playing a recording.
shadow.moveLogic();
//Let the shadow jump.
shadow.jump();
//Let the shadow move.
shadow.move(levelObjects);
//Some levelObjects can move so update them.
for(unsigned int i=0;i<levelObjects.size();i++){
levelObjects[i]->move();
}
//Process any event in the queue.
for(unsigned int idx=0;idx<eventQueue.size();idx++){
//Get the event from the queue.
typeGameObjectEvent &e=eventQueue[idx];
//Check if the it has an id attached to it.
if(e.flags|1){
//Loop through the levelObjects and give them the event if they have the right id.
for(unsigned int i=0;i<levelObjects.size();i++){
if(e.objectType<0 || levelObjects[i]->type==e.objectType){
Block *obj=dynamic_cast<Block*>(levelObjects[i]);
if(obj!=NULL && obj->id==e.id){
levelObjects[i]->onEvent(e.eventType);
}
}
}
}else{
//Loop through the levelObjects and give them the event.
for(unsigned int i=0;i<levelObjects.size();i++){
if(e.objectType<0 || levelObjects[i]->type==e.objectType){
levelObjects[i]->onEvent(e.eventType);
}
}
}
}
//Done processing the events so clear the queue.
eventQueue.clear();
//Check collision and stuff for the shadow and player.
player.otherCheck(&shadow);
//Check if we won.
if(won){
//the string to store auto-save record path.
string bestTimeFilePath,bestRecordingFilePath;
//and if we can't get test path.
bool filePathError=false;
//Set the current level won.
levels->getLevel()->won=true;
if(levels->getLevel()->time==-1 || levels->getLevel()->time>time){
levels->getLevel()->time=time;
//save the best-time game record.
if(bestTimeFilePath.empty()){
getCurrentLevelAutoSaveRecordPath(bestTimeFilePath,bestRecordingFilePath,true);
}
if(bestTimeFilePath.empty()){
cout<<"ERROR: Couldn't get auto-save record file path"<<endl;
filePathError=true;
}else{
saveRecord(bestTimeFilePath.c_str());
}
}
if(levels->getLevel()->recordings==-1 || levels->getLevel()->recordings>recordings){
levels->getLevel()->recordings=recordings;
//save the best-recordings game record.
if(bestRecordingFilePath.empty() && !filePathError){
getCurrentLevelAutoSaveRecordPath(bestTimeFilePath,bestRecordingFilePath,true);
}
if(bestRecordingFilePath.empty()){
cout<<"ERROR: Couldn't get auto-save record file path"<<endl;
filePathError=true;
}else{
saveRecord(bestRecordingFilePath.c_str());
}
}
//Set the next level unlocked if it exists.
if(levels->getCurrentLevel()+1<levels->getLevelCount()){
levels->setLocked(levels->getCurrentLevel()+1);
}
//And save the progress.
levels->saveLevelProgress();
//Now go to the interlevel screen.
replayPlay();
//NOTE: We set isReset false to prevent the user from getting a best time of 0.00s and 0 recordings.
}
won=false;
//Check if we should reset.
if(isReset)
reset(false);
isReset=false;
}
/////////////////RENDER//////////////////
void Game::render(){
//First of all render the background.
{
//Get a pointer to the background.
ThemeBackground* bg=background;
//Check if the background is null, but there are themes.
if(bg==NULL && objThemes.themeCount()>0){
//Get the background from the first theme in the stack.
bg=objThemes[0]->getBackground();
}
//Check if the background isn't null.
if(bg){
//It isn't so draw it.
bg->draw(screen);
//And if it's the loaded background then also update the animation.
//FIXME: Updating the animation in the render method?
if(bg==background)
bg->updateAnimation();
}else{
//There's no background so fill the screen with white.
SDL_Rect r={0,0,SCREEN_WIDTH,SCREEN_HEIGHT};
SDL_FillRect(screen,&r,-1);
}
}
//Now we draw the levelObjects.
for(unsigned int o=0; o<levelObjects.size(); o++){
levelObjects[o]->show();
}
//Followed by the player and the shadow.
player.show();
shadow.show();
//Show the levelName if it isn't the level editor.
if(stateID!=STATE_LEVEL_EDITOR && bmTips[0]!=NULL && !interlevel){
applySurface(0,SCREEN_HEIGHT-bmTips[0]->h,bmTips[0],screen,NULL);
}
//Check if there's a tooltip.
//NOTE: gameTipIndex 0 is used for the levelName, 1 for shadow death, 2 for restart text, 3 for restart+checkpoint.
if(gameTipIndex>3 && gameTipIndex<TYPE_MAX){
//Check if there's a tooltip for the type.
if(bmTips[gameTipIndex]==NULL){
//There isn't thus make it.
- const char* s=NULL;
+ string s;
string keyCode=inputMgr.getKeyCodeName(inputMgr.getKeyCode(INPUTMGR_ACTION,false));
transform(keyCode.begin(),keyCode.end(),keyCode.begin(),::toupper);
switch(gameTipIndex){
case TYPE_CHECKPOINT:
/// TRANSLATORS: Please do not remove %s from your translation:
/// - %s will be replaced with current action key
- s=tfm::format(_("Press %s key to save the game."),keyCode).c_str();
+ s=tfm::format(_("Press %s key to save the game."),keyCode);
break;
case TYPE_SWAP:
/// TRANSLATORS: Please do not remove %s from your translation:
/// - %s will be replaced with current action key
- s=tfm::format("Press %s key to swap the position of player and shadow.",keyCode).c_str();
+ s=tfm::format(_("Press %s key to swap the position of player and shadow."),keyCode);
break;
case TYPE_SWITCH:
/// TRANSLATORS: Please do not remove %s from your translation:
/// - %s will be replaced with current action key
- s=tfm::format("Press %s key to activate the switch.",keyCode).c_str();
+ s=tfm::format(_("Press %s key to activate the switch."),keyCode);
break;
case TYPE_PORTAL:
/// TRANSLATORS: Please do not remove %s from your translation:
/// - %s will be replaced with current action key
- s=tfm::format("Press %s key to teleport.",keyCode).c_str();
+ s=tfm::format(_("Press %s key to teleport."),keyCode);
break;
}
//If we have a string then it's a supported GameObject type.
- if(s!=NULL){
+ if(!s.empty()){
SDL_Color fg={0,0,0,0},bg={255,255,255,0};
- bmTips[gameTipIndex]=TTF_RenderUTF8_Shaded(fontText,s,fg,bg);
+ bmTips[gameTipIndex]=TTF_RenderUTF8_Shaded(fontText,s.c_str(),fg,bg);
SDL_SetAlpha(bmTips[gameTipIndex],SDL_SRCALPHA,160);
}
}
//We already have a gameTip for this type so draw it.
if(bmTips[gameTipIndex]!=NULL){
applySurface(0,0,bmTips[gameTipIndex],screen,NULL);
}
}
//Set the gameTip to 0.
gameTipIndex=0;
//Pointer to the sdl surface that will contain a message, if any.
SDL_Surface* bm=NULL;
//Check if the player is dead, meaning we draw a message.
if(player.dead){
//Get user configured restart key
string keyCodeRestart=inputMgr.getKeyCodeName(inputMgr.getKeyCode(INPUTMGR_RESTART,false));
transform(keyCodeRestart.begin(),keyCodeRestart.end(),keyCodeRestart.begin(),::toupper);
//The player is dead, check if there's a state that can be loaded.
if(player.canLoadState()){
//Now check if the tip is already made, if not make it.
if(bmTips[3]==NULL){
//Get user defined key for loading checkpoint
string keyCodeLoad=inputMgr.getKeyCodeName(inputMgr.getKeyCode(INPUTMGR_LOAD,false));
transform(keyCodeLoad.begin(),keyCodeLoad.end(),keyCodeLoad.begin(),::toupper);
//Draw string
SDL_Color fg={0,0,0,0},bg={255,255,255,0};
bmTips[3]=TTF_RenderUTF8_Shaded(fontText,
/// TRANSLATORS: Please do not remove %s from your translation:
/// - first %s means currently configured key to restart game
/// - Second %s means configured key to load from last save
tfm::format(_("Press %s to restart current level or press %s to load the game."),
keyCodeRestart,keyCodeLoad).c_str(),
fg,bg);
SDL_SetAlpha(bmTips[3],SDL_SRCALPHA,160);
}
bm=bmTips[3];
}else{
//Now check if the tip is already made, if not make it.
if(bmTips[2]==NULL){
SDL_Color fg={0,0,0,0},bg={255,255,255,0};
bmTips[2]=TTF_RenderUTF8_Shaded(fontText,
/// TRANSLATORS: Please do not remove %s from your translation:
/// - %s will be replaced with currently configured key to restart game
tfm::format(_("Press %s to restart current level."),keyCodeRestart).c_str(),
fg,bg);
SDL_SetAlpha(bmTips[2],SDL_SRCALPHA,160);
}
bm=bmTips[2];
}
}
//Check if the shadow has died (and there's no other notification).
//NOTE: We use the shadow's jumptime as countdown, this variable isn't used when the shadow is dead.
if(shadow.dead && bm==NULL && shadow.jumpTime>0){
//Now check if the tip is already made, if not make it.
if(bmTips[1]==NULL){
SDL_Color fg={0,0,0,0},bg={255,255,255,0};
bmTips[1]=TTF_RenderUTF8_Shaded(fontText,
_("Your shadow has died."),
fg,bg);
SDL_SetAlpha(bmTips[1],SDL_SRCALPHA,160);
}
bm=bmTips[1];
//NOTE: Logic in the render loop, we substract the shadow's jumptime by one.
shadow.jumpTime--;
}
//Draw the tip.
if(bm!=NULL)
applySurface(0,0,bm,screen,NULL);
//show time and records used in level editor.
if(stateID==STATE_LEVEL_EDITOR && time>0){
SDL_Color fg={0,0,0,0},bg={255,255,255,0};
SDL_Surface *bm;
int y=SCREEN_HEIGHT;
bm=TTF_RenderUTF8_Shaded(fontText,tfm::format(_("%d recordings"),recordings).c_str(),fg,bg);
SDL_SetAlpha(bm,SDL_SRCALPHA,160);
y-=bm->h;
applySurface(0,y,bm,screen,NULL);
SDL_FreeSurface(bm);
char c[32];
sprintf(c,"%-.2fs",time/40.0f);
bm=TTF_RenderUTF8_Shaded(fontText,c,fg,bg);
SDL_SetAlpha(bm,SDL_SRCALPHA,160);
y-=bm->h;
applySurface(0,y,bm,screen,NULL);
SDL_FreeSurface(bm);
}
//Draw the current action in the upper right corner.
if(player.record){
applySurface(SCREEN_WIDTH-50,0,action,screen,NULL);
}else if(shadow.state!=0){
SDL_Rect r={50,0,50,50};
applySurface(SCREEN_WIDTH-50,0,action,screen,&r);
}
//if the game is play from record then draw something indicates it
if(player.isPlayFromRecord()){
//Dim the screen if interlevel is true.
if(interlevel){
SDL_BlitSurface(screen,NULL,tempSurface,NULL);
SDL_FillRect(screen,NULL,0);
SDL_SetAlpha(tempSurface, SDL_SRCALPHA,220);
SDL_BlitSurface(tempSurface,NULL,screen,NULL);
//Check if the GUI isn't null.
if(GUIObjectRoot){
//==Create first box==
//Create the title
SDL_Color black={0,0,0,0};
SDL_Rect r;
/// TRANSLATORS: This is caption for finished level
SDL_Surface* bm=TTF_RenderUTF8_Blended(fontGUI,_("You've finished:"),black);
//Recreate the level string.
string s;
if (levels->getLevelCount()>0){
/// TRANSLATORS: Please do not remove %s or %d from your translation:
/// - %d means the level number in a levelpack
/// - %s means the name of current level
s=tfm::format(_("Level %d %s"),levels->getCurrentLevel()+1,levelName);
}
SDL_Surface* bm2=TTF_RenderUTF8_Blended(fontText,s.c_str(),black);
//Now draw the first gui box so that it's bigger than longer text.
int width;
if(bm->w>bm2->w)
width=bm->w+32;
else
width=bm2->w+32;
drawGUIBox((SCREEN_WIDTH-width)/2,4,width,68,screen,0xDDDDDDA1);
// Now draw title.
r.x=(SCREEN_WIDTH-bm->w)/2;
r.y=8;
SDL_BlitSurface(bm,NULL,screen,&r);
// And then level name.
r.x=(SCREEN_WIDTH-bm2->w)/2;
r.y=44;
SDL_BlitSurface(bm2,NULL,screen,&r);
//Free drawed texts
SDL_FreeSurface(bm);
SDL_FreeSurface(bm2);
//==Create second box==
//Now draw the second gui box.
drawGUIBox(GUIObjectRoot->left,GUIObjectRoot->top,GUIObjectRoot->width,GUIObjectRoot->height,screen,0xDDDDDDA1);
//Draw the medal.
int medal=GUIObjectRoot->value;
r.x=(medal-1)*30;
r.y=0;
r.w=30;
r.h=30;
applySurface(GUIObjectRoot->left+16,GUIObjectRoot->top+92,medals,screen,&r);
applySurface(GUIObjectRoot->left+370,GUIObjectRoot->top+92,medals,screen,&r);
}
}else if((time & 0x10)==0x10){
SDL_Rect r={50,0,50,50};
applySurface(0,0,action,screen,&r);
applySurface(0,SCREEN_HEIGHT-50,action,screen,&r);
applySurface(SCREEN_WIDTH-50,SCREEN_HEIGHT-50,action,screen,&r);
}
}else if(player.objNotificationBlock){
//If the player is in front of a notification block show the message.
//And it isn't a replay.
std::string &untranslated_message=(dynamic_cast<Block*>(player.objNotificationBlock))->message;
std::string message=_C(levels->getDictionaryManager(),untranslated_message);
std::vector<char> string_data(message.begin(), message.end());
string_data.push_back('\0');
int y = 20;
vector<SDL_Surface*> lines;
//Now process the prompt.
{
//Pointer to the string.
char* lps=&string_data[0];
//Pointer to a character.
char* lp=NULL;
//We keep looping forever.
//The only way out is with the break statement.
for(;;){
//As long as it's still the same sentence we continue.
//It will stop when there's a newline or end of line.
for(lp=lps;*lp!='\n'&&*lp!='\r'&&*lp!=0;lp++);
//Store the character we stopped on. (End or newline)
char c=*lp;
//Set the character in the string to 0, making lps a string containing one sentence.
*lp=0;
//Integer used to center the sentence horizontally.
int x;
TTF_SizeText(fontText,lps,&x,NULL);
x=(SCREEN_WIDTH-200-x)/2;
//Color the text will be: black.
SDL_Color black={0,0,0,0};
lines.push_back(TTF_RenderUTF8_Blended(fontText,lps,black));
//Increase y with 25, about the height of the text.
y+=25;
//Check the stored character if it was a stop.
if(c==0){
//It was so break out of the for loop.
lps=lp;
break;
}
//It wasn't meaning more will follow.
//We set lps to point after the "newline" forming a new string.
lps=lp+1;
}
}
drawGUIBox(100,SCREEN_HEIGHT-y-25,SCREEN_WIDTH-200,y+20,screen,0xDDDDDDA1);
while(!lines.empty()){
SDL_Surface* bm=lines[0];
if(bm!=NULL){
applySurface(100+((SCREEN_WIDTH-200-bm->w)/2),SCREEN_HEIGHT-y,bm,screen,NULL);
SDL_FreeSurface(bm);
}
y-=25;
lines.erase(lines.begin());
}
}
}
void Game::replayPlay(){
interlevel=true;
//cout<<"Game::replayPlay()"<<endl;
//Fix the bug that press "r" to restart a level just before finishing it
//will cause inter-level popup appeares and the game restarts.
//Now when the game is about to finish, we don't allow to restart.
isReset=false;
//Create the gui if it isn't already done.
if(!GUIObjectRoot){
GUIObjectRoot=new GUIObject((SCREEN_WIDTH-570)/2,SCREEN_HEIGHT-140,570,135,GUIObjectNone);
//NOTE: We put the medal in the value of the GUIObjectRoot.
//The different values.
int bestTime=levels->getLevel()->time;
int targetTime=levels->getLevel()->targetTime;
int bestRecordings=levels->getLevel()->recordings;
int targetRecordings=levels->getLevel()->targetRecordings;
int medal=1;
if(targetTime<0){
medal=3;
}else{
if(targetTime<0 || bestTime<=targetTime)
medal++;
if(targetRecordings<0 || bestRecordings<=targetRecordings)
medal++;
}
//Add it to the GUIObjectRoot.
GUIObjectRoot->value=medal;
//Create the labels with the time and best time.
/// TRANSLATORS: Please do not remove %-.2f from your translation:
/// - %-.2f means time in seconds
/// - s is shortened form of a second. Try to keep it so.
GUIObject* obj=new GUIObject(20,10,150,36,GUIObjectLabel,tfm::format(_("Time: %-.2fs"),time/40.0f).c_str());
GUIObjectRoot->childControls.push_back(obj);
/// TRANSLATORS: Please do not remove %-.2f from your translation:
/// - %-.2f means time in seconds
/// - s is shortened form of a second. Try to keep it so.
obj=new GUIObject(20,34,150,36,GUIObjectLabel,tfm::format(_("Best time: %-.2fs"),bestTime/40.0f).c_str());
GUIObjectRoot->childControls.push_back(obj);
/// TRANSLATORS: Please do not remove %-.2f from your translation:
/// - %-.2f means time in seconds
/// - s is shortened form of a second. Try to keep it so.
if(targetTime>=0){
obj=new GUIObject(20,58,150,36,GUIObjectLabel,tfm::format(_("Target time: %-.2fs"),targetTime/40.0f).c_str());
GUIObjectRoot->childControls.push_back(obj);
}
//Now the ones for the recordings.
/// TRANSLATORS: Please do not remove %d from your translation:
/// - %d means the number of recordings user has made
obj=new GUIObject(210,10,150,36,GUIObjectLabel,tfm::format(_("Recordings: %d"),recordings).c_str());
GUIObjectRoot->childControls.push_back(obj);
/// TRANSLATORS: Please do not remove %d from your translation:
/// - %d means the number of recordings user has made
obj=new GUIObject(210,34,150,36,GUIObjectLabel,tfm::format(_("Best recordings: %d"),bestRecordings).c_str());
GUIObjectRoot->childControls.push_back(obj);
/// TRANSLATORS: Please do not remove %d from your translation:
/// - %d means the number of recordings user has made
if(targetRecordings>=0){
obj=new GUIObject(210,58,150,36,GUIObjectLabel,tfm::format(_("Target recordings: %d"),targetRecordings).c_str());
GUIObjectRoot->childControls.push_back(obj);
}
//The medal that is earned.
/// TRANSLATORS: Please do not remove %s from your translation:
/// - %s will be replaced with name of a prize medal (gold, silver or bronze)
string s1=tfm::format(_("You earned the %s medal"),(medal>1)?(medal==3)?_("GOLD"):_("SILVER"):_("BRONZE"));
obj=new GUIObject(48,92,150,36,GUIObjectLabel,s1.c_str());
//Center it horizontally.
int width;
TTF_SizeText(fontText,s1.c_str(),&width,NULL);
obj->width=width;
obj->left=(416-width)/2;
GUIObjectRoot->childControls.push_back(obj);
//Create the three buttons, Menu, Restart, Next.
/// TRANSLATORS: used as return to the level selector menu
obj=new GUIObject(420,10,128,36,GUIObjectButton,_("Menu"));
obj->name="cmdMenu";
obj->eventCallback=this;
GUIObjectRoot->childControls.push_back(obj);
/// TRANSLATORS: used as restart level
obj=new GUIObject(409,50,150,36,GUIObjectButton,_("Restart"));
obj->name="cmdRestart";
obj->eventCallback=this;
GUIObjectRoot->childControls.push_back(obj);
/// TRANSLATORS: used as next level
obj=new GUIObject(420,90,128,36,GUIObjectButton,_("Next"));
obj->name="cmdNext";
obj->eventCallback=this;
GUIObjectRoot->childControls.push_back(obj);
}
//We only need to reset a few things so we don't call reset().
for(unsigned int i=0;i<levelObjects.size();i++){
levelObjects[i]->reset(true);
}
//Also reset the background animation, if any.
if(background)
background->resetAnimation(true);
//Make a copy of the playerButtons.
vector<int> recordCopy=player.recordButton;
player.reset(true);
shadow.reset(true);
player.recordButton=recordCopy;
//Now play the recording.
player.playRecord();
}
void Game::recordingEnded(){
//Check if it's a normal replay, if so just stop.
if(!interlevel){
msgBox(_("Game replay is done."),MsgBoxOKOnly,_("Game Replay"));
//Go to the level select menu.
setNextState(STATE_LEVEL_SELECT);
//And change the music back to the menu music.
getMusicManager()->playMusic("menu");
}else{
//Instead of directly replaying we set won true to let the Game handle the replaying at the end of the update cycle.
won=true;
}
}
bool Game::saveState(){
//Check if the player and shadow can save the current state.
if(player.canSaveState() && shadow.canSaveState()){
//Let the player and the shadow save their state.
player.saveState();
shadow.saveState();
//Save the stats.
timeSaved=time;
recordingsSaved=recordings;
//Save other state, for example moving blocks.
for(unsigned int i=0;i<levelObjects.size();i++){
levelObjects[i]->saveState();
}
//Also save the background animation, if any.
if(background)
background->saveAnimation();
//Return true.
return true;
}
//We can't save the state so return false.
return false;
}
bool Game::loadState(){
//Check if there's a state that can be loaded.
if(player.canLoadState() && shadow.canLoadState()){
//Let the player and the shadow load their state.
player.loadState();
shadow.loadState();
//Load the stats.
time=timeSaved;
recordings=recordingsSaved;
//Load other state, for example moving blocks.
for(unsigned int i=0;i<levelObjects.size();i++){
levelObjects[i]->loadState();
}
//Also load the background animation, if any.
if(background)
background->loadAnimation();
//Return true.
return true;
}
//We can't load the state so return false.
return false;
}
void Game::reset(bool save){
//We need to reset the game so we also reset the player and the shadow.
player.reset(save);
shadow.reset(save);
//Reset the stats.
time=0;
recordings=0;
//There is no last checkpoint so set it to NULL.
if(save)
objLastCheckPoint=NULL;
//Reset other state, for example moving blocks.
for(unsigned int i=0;i<levelObjects.size();i++){
levelObjects[i]->reset(save);
}
//Also reset the background animation, if any.
if(background)
background->resetAnimation(save);
//Also set interlevel to false.
interlevel=false;
}
void Game::broadcastObjectEvent(int eventType,int objectType,const char* id){
//Create a typeGameObjectEvent that can be put into the queue.
typeGameObjectEvent e;
//Set the event type.
e.eventType=eventType;
//Set the object type.
e.objectType=objectType;
//By default flags=0.
e.flags=0;
//Unless there's an id.
if(id){
//Set flags to 0x1 and set the id.
e.flags|=1;
e.id=id;
}
//Add the event to the queue.
eventQueue.push_back(e);
}
void Game::getCurrentLevelAutoSaveRecordPath(std::string &bestTimeFilePath,std::string &bestRecordingFilePath,bool createPath){
levels->getLevelAutoSaveRecordPath(-1,bestTimeFilePath,bestRecordingFilePath,createPath);
}
void Game::gotoNextLevel(){
//Goto the next level.
levels->nextLevel();
//Check if the level exists.
if(levels->getCurrentLevel()<levels->getLevelCount()){
setNextState(STATE_GAME);
//Don't forget the music.
getMusicManager()->pickMusic();
}else{
if(!levels->congratulationText.empty()){
msgBox(_C(levels->getDictionaryManager(),levels->congratulationText),MsgBoxOKOnly,_("Congratulations"));
}else{
msgBox(_("You have finished the levelpack!"),MsgBoxOKOnly,_("Congratulations"));
}
//Now go back to the levelselect screen.
setNextState(STATE_LEVEL_SELECT);
//And set the music back to menu.
getMusicManager()->playMusic("menu");
}
}
void Game::GUIEventCallback_OnEvent(string name,GUIObject* obj,int eventType){
if(name=="cmdMenu"){
setNextState(STATE_LEVEL_SELECT);
//And change the music back to the menu music.
getMusicManager()->playMusic("menu");
}else if(name=="cmdRestart"){
//Clear the gui.
if(GUIObjectRoot){
delete GUIObjectRoot;
GUIObjectRoot=NULL;
}
//And reset the game.
//new: we don't need to clear the save game because
//in level replay the game won't be saved
//TODO: it doesn't work; better leave for next release
reset(/*false*/ true);
}else if(name=="cmdNext"){
//No matter what, clear the gui.
if(GUIObjectRoot){
delete GUIObjectRoot;
GUIObjectRoot=NULL;
}
//And goto the next level.
gotoNextLevel();
}
}
diff --git a/src/LevelSelect.cpp b/src/LevelSelect.cpp
index bdf6964..8d03bf2 100644
--- a/src/LevelSelect.cpp
+++ b/src/LevelSelect.cpp
@@ -1,326 +1,326 @@
/****************************************************************************
** Copyright (C) 2011 Luka Horvat <redreaper132 at gmail.com>
** Copyright (C) 2011 Edward Lii <edward_iii at myway.com>
** Copyright (C) 2011 O. Bahri Gordebak <gordebak at gmail.com>
**
**
** This file may be used under the terms of the GNU General Public
** License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of
** this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
**
****************************************************************************/
#include "GameState.h"
#include "Functions.h"
#include "FileManager.h"
#include "Globals.h"
#include "Objects.h"
#include "LevelSelect.h"
#include "GUIObject.h"
#include "GUIListBox.h"
#include "GUIScrollBar.h"
#include "InputManager.h"
#include "Game.h"
#include <SDL/SDL_ttf.h>
#include <SDL/SDL.h>
#include <stdio.h>
#include <string>
#include <sstream>
#include <iostream>
#include "libs/tinyformat/tinyformat.h"
using namespace std;
////////////////////NUMBER////////////////////////
Number::Number(){
image=NULL;
number=0;
medal=0;
selected=false;
locked=false;
//Set the default dimensions.
box.x=0;
box.y=0;
box.h=50;
box.w=50;
//Load the medals image.
background=loadImage(getDataPath()+"gfx/level.png");
backgroundLocked=loadImage(getDataPath()+"gfx/levellocked.png");
medals=loadImage(getDataPath()+"gfx/medals.png");
}
Number::~Number(){
//We only need to free the SDLSurface.
if(image) SDL_FreeSurface(image);
}
void Number::init(int number,SDL_Rect box){
//First set the number and update our status.
this->number=number;
//Write our text, number+1 since the counting doens't start with 0, but with 1.
std::stringstream text;
number++;
text<<number;
//Create the text image.
SDL_Color black={0,0,0};
if(image) SDL_FreeSurface(image);
//Create the text image.
//Also check which font to use, if the number is higher than 100 use the small font.
image=TTF_RenderUTF8_Blended(fontGUI,text.str().c_str(),black);
//Set the new location of the number.
this->box.x=box.x;
this->box.y=box.y;
}
void Number::init(std::string text,SDL_Rect box){
//First set the number and update our status.
this->number=-1;
//Create the text image.
SDL_Color black={0,0,0};
if(image) SDL_FreeSurface(image);
image=TTF_RenderUTF8_Blended(fontGUI,text.c_str(),black);
//Set the new location of the number.
this->box.x=box.x;
this->box.y=box.y;
}
void Number::show(int dy){
//First draw the background, also apply the yOffset(dy).
if(!locked)
applySurface(box.x,box.y-dy,background,screen,NULL);
else
applySurface(box.x,box.y-dy,backgroundLocked,screen,NULL);
//Now draw the text image over the background.
//We draw it centered inside the box.
applySurface((box.x+25-(image->w/2)),box.y+((TTF_FontAscent(fontGUI)+TTF_FontDescent(fontGUI))/2)-dy,image,screen,NULL);
//Draw the selection mark.
if(selected){
drawGUIBox(box.x,box.y-dy,50,50,screen,0xFFFFFF23);
}
//Draw the medal.
if(medal>0){
SDL_Rect r={(medal-1)*30,0,30,30};
applySurface(box.x+30,(box.y+30)-dy,medals,screen,&r);
}
}
void Number::setLocked(bool locked){
this->locked=locked;
}
void Number::setMedal(int medal){
this->medal=medal;
}
/////////////////////LEVEL SELECT/////////////////////
LevelSelect::LevelSelect(string titleText,LevelPackManager::LevelPackLists packType){
//clear the selected level
selectedNumber=NULL;
//Calculate the LEVELS_PER_ROW and LEVEL_ROWS if they aren't calculated already.
- LEVELS_PER_ROW=ceil((SCREEN_WIDTH-160)/64);
- int LEVEL_ROWS=ceil(SCREEN_HEIGHT-344)/64;
+ LEVELS_PER_ROW=(SCREEN_WIDTH-160)/64;
+ int LEVEL_ROWS=(SCREEN_HEIGHT-344)/64;
LEVELS_DISPLAYED_IN_SCREEN=LEVELS_PER_ROW*LEVEL_ROWS;
//Render the title.
SDL_Color black={0,0,0};
title=TTF_RenderUTF8_Blended(fontTitle,titleText.c_str(),black);
//create GUI (test only)
GUIObject* obj;
if(GUIObjectRoot){
delete GUIObjectRoot;
GUIObjectRoot=NULL;
}
GUIObjectRoot=new GUIObject(0,0,SCREEN_WIDTH,SCREEN_HEIGHT);
//the level select scroll bar
levelScrollBar=new GUIScrollBar(SCREEN_WIDTH-64,184,16,242,ScrollBarVertical,0,0,0,1,4,true,false);
GUIObjectRoot->childControls.push_back(levelScrollBar);
//level pack description
levelpackDescription=new GUIObject(60,140,800,32,GUIObjectLabel);
GUIObjectRoot->childControls.push_back(levelpackDescription);
levelpacks=new GUISingleLineListBox((SCREEN_WIDTH-500)/2,104,500,32);
levelpacks->name="cmdLvlPack";
levelpacks->eventCallback=this;
vector<string> v=getLevelPackManager()->enumLevelPacks(packType);
levelpacks->item=v;
levelpacks->value=0;
//Check if we can find the lastlevelpack.
for(vector<string>::iterator i=v.begin(); i!=v.end(); ++i){
if(*i==getSettings()->getValue("lastlevelpack")){
levelpacks->value=i-v.begin();
}
}
//Get the name of the selected levelpack.
string levelpackName=levelpacks->item[levelpacks->value];
string s1=getUserPath(USER_DATA)+"progress/"+levelpackName+".progress";
//Load the progress.
levels=getLevelPackManager()->getLevelPack(v[levelpacks->value]);
levels->loadProgress(s1);
//And add the levelpack single line listbox to the GUIObjectRoot.
GUIObjectRoot->childControls.push_back(levelpacks);
obj=new GUIObject(20,20,100,32,GUIObjectButton,_("Back"));
obj->name="cmdBack";
obj->eventCallback=this;
GUIObjectRoot->childControls.push_back(obj);
}
LevelSelect::~LevelSelect(){
if(GUIObjectRoot){
delete GUIObjectRoot;
GUIObjectRoot=NULL;
}
levelScrollBar=NULL;
levelpackDescription=NULL;
selectedNumber=NULL;
//Free the rendered title surface.
SDL_FreeSurface(title);
}
void LevelSelect::handleEvents(){
//Check for an SDL_QUIT event.
if(event.type==SDL_QUIT){
setNextState(STATE_EXIT);
}
//Check for a mouse click.
if(event.type==SDL_MOUSEBUTTONUP && event.button.button==SDL_BUTTON_LEFT){
checkMouse();
}
//Check if escape is pressed.
if(inputMgr.isKeyUpEvent(INPUTMGR_ESCAPE)){
setNextState(STATE_MENU);
}
//Check for scrolling down and up.
if(event.type==SDL_MOUSEBUTTONDOWN && event.button.button==SDL_BUTTON_WHEELDOWN && levelScrollBar){
if(levelScrollBar->value<levelScrollBar->maxValue) levelScrollBar->value++;
return;
}else if(event.type==SDL_MOUSEBUTTONDOWN && event.button.button==SDL_BUTTON_WHEELUP && levelScrollBar){
if(levelScrollBar->value>0) levelScrollBar->value--;
return;
}
}
void LevelSelect::checkMouse(){
int x,y,dy=0,m=numbers.size();
//Get the current mouse location.
SDL_GetMouseState(&x,&y);
//Check if there's a scrollbar, if so get the value.
if(levelScrollBar)
dy=levelScrollBar->value;
//Upper bound of levels we'd like to display.
if(m>dy*LEVELS_PER_ROW+LEVELS_DISPLAYED_IN_SCREEN)
m=dy*LEVELS_PER_ROW+LEVELS_DISPLAYED_IN_SCREEN;
y+=dy*64;
SDL_Rect mouse={x,y,0,0};
for(int n=dy*LEVELS_PER_ROW; n<m; n++){
if(!numbers[n].getLocked()){
if(checkCollision(mouse,numbers[n].box)==true){
if(numbers[n].selected){
selectNumber(n,true);
}else{
//Select current level
for(int i=0;i<levels->getLevelCount();i++){
numbers[i].selected=(i==n);
}
selectNumber(n,false);
}
break;
}
}
}
}
void LevelSelect::logic(){}
void LevelSelect::render(){
int x,y,dy=0,m=numbers.size();
int idx=-1;
//Get the current mouse location.
SDL_GetMouseState(&x,&y);
if(levelScrollBar)
dy=levelScrollBar->value;
//Upper bound of levels we'd like to display.
if(m>dy*LEVELS_PER_ROW+LEVELS_DISPLAYED_IN_SCREEN)
m=dy*LEVELS_PER_ROW+LEVELS_DISPLAYED_IN_SCREEN;
y+=dy*64;
SDL_Rect mouse={x,y,0,0};
//Draw the menu background.
applySurface(0,0,menuBackground,screen,NULL);
//Draw the title.
applySurface((SCREEN_WIDTH-title->w)/2,40,title,screen,NULL);
//Loop through the level blocks and draw them.
for(int n=dy*LEVELS_PER_ROW;n<m;n++){
numbers[n].show(dy*64);
if(numbers[n].getLocked()==false && checkCollision(mouse,numbers[n].box)==true)
idx=n;
}
//Show the tool tip text.
if(idx>=0){
renderTooltip(idx,dy);
}
}
void LevelSelect::GUIEventCallback_OnEvent(std::string name,GUIObject* obj,int eventType){
string s;
if(name=="cmdLvlPack"){
getSettings()->setValue("lastlevelpack",((GUISingleLineListBox*)obj)->item[obj->value]);
}else if(name=="cmdBack"){
setNextState(STATE_MENU);
return;
}else{
return;
}
//new: reset the level list scroll bar
if(levelScrollBar)
levelScrollBar->value=0;
string s1=getUserPath(USER_DATA)+"progress/"+((GUISingleLineListBox*)obj)->item[obj->value]+".progress";
levels=getLevelPackManager()->getLevelPack(((GUISingleLineListBox*)obj)->item[obj->value]);
//Load the progress file.
levels->loadProgress(s1);
//And refresh the numbers.
refresh();
}
diff --git a/src/Main.cpp b/src/Main.cpp
index 40228a3..d1a85db 100644
--- a/src/Main.cpp
+++ b/src/Main.cpp
@@ -1,182 +1,187 @@
/****************************************************************************
** Copyright (C) 2011 Luka Horvat <redreaper132 at gmail.com>
** Copyright (C) 2011 Edward Lii <edward_iii at myway.com>
** Copyright (C) 2011 O. Bahri Gordebak <gordebak at gmail.com>
**
**
** This file may be used under the terms of the GNU General Public
** License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of
** this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
**
****************************************************************************/
#include "Functions.h"
#include "Timer.h"
#include "Objects.h"
#include "Globals.h"
#include "TitleMenu.h"
#include "GUIObject.h"
#include "InputManager.h"
#include "MD5.h"
#include <SDL/SDL.h>
#include <stdlib.h>
#include <time.h>
#include <stdio.h>
#include <string.h>
+#include "libs/tinygettext/log.hpp"
+
#ifdef HARDWARE_ACCELERATION
#include <GL/gl.h>
#include <GL/glu.h>
#endif
//Variables for recording.
//To enable picture recording uncomment the next line:
//#define RECORD_PICUTRE_SEQUENCE
#ifdef RECORD_PICUTRE_SEQUENCE
bool recordPictureSequence=false;
int recordPictureIndex=0;
#endif
int main(int argc, char** argv) {
#ifdef _MSC_VER
//Fix the non-latin file name bug under Visual Studio
setlocale(LC_ALL,"");
#endif
//First parse the comand line arguments.
if(!parseArguments(argc,argv)){
printf("Usage: %s [OPTIONS] ...\n",argv[0]);
printf("Avaliable options:\n");
printf(" %-20s %s\n","--data-dir <dir>","Specifies the data directory.");
printf(" %-20s %s\n","--user-dir <dir>","Specifies the user preferences directory.");
printf(" %-20s %s\n","--version","Display the version and quit.");
printf(" %-20s %s\n","--help","Display this help.");
return 0;
}
+ //disable annoying 'Couldn't translate: blah blah blah'
+ tinygettext::Log::set_log_info_callback(NULL);
+
//Try to configure the dataPath, userPath, etc...
if(configurePaths()==false){
fprintf(stderr,"FATAL ERROR: Failed to configure paths.\n");
return 1;
}
//Load the settings.
if(loadSettings()==false){
fprintf(stderr,"FATAL ERROR: Failed to load config file.\n");
return 1;
}
//Initialise some stuff like SDL, the window, SDL_Mixer.
if(init()==false) {
fprintf(stderr,"FATAL ERROR: Failed to initalize game.\n");
return 1;
}
//Load some important files like the background music, default theme.
if(loadFiles()==false){
fprintf(stderr,"FATAL ERROR: Failed to load necessary files.\n");
return 1;
}
//Load key config. Then initalize joystick support.
inputMgr.loadConfig();
inputMgr.openAllJoysitcks();
//Load the configured music list.
getMusicManager()->loadMusicList((getDataPath()+"music/"+getSettings()->getValue("musiclist")+".list"));
getMusicManager()->setMusicList(getSettings()->getValue("musiclist"));
//Set the currentState id to the main menu and create it.
stateID=STATE_MENU;
currentState=new Menu();
//Seed random.
srand((unsigned)time(NULL));
//Check if sound is enabled.
if(getSettings()->getBoolValue("music"))
getMusicManager()->setEnabled();
//Create the temp surface, just a replica of the screen surface.
tempSurface=SDL_CreateRGBSurface(SDL_HWSURFACE|SDL_SRCALPHA,
screen->w,screen->h,screen->format->BitsPerPixel,
screen->format->Rmask,screen->format->Gmask,screen->format->Bmask,0);
int fadeIn=0;
//Start the game loop.
while(stateID!=STATE_EXIT){
//We start the timer.
FPS.start();
//Loop the SDL events.
while(SDL_PollEvent(&event)){
#ifdef RECORD_PICUTRE_SEQUENCE
if(event.type==SDL_KEYDOWN && event.key.keysym.sym==SDLK_F10){
recordPictureSequence=!recordPictureSequence;
printf("Record Picture Sequence %s\n",recordPictureSequence?"ON":"OFF");
}
#endif
//Let the input manager handle the events.
inputMgr.updateState(true);
//Let the currentState handle the events.
currentState->handleEvents();
//Also pass the events to the GUI.
GUIObjectHandleEvents();
}
//update input state (??)
inputMgr.updateState(false);
//Now it's time for the state to do his logic.
currentState->logic();
currentState->render();
//TODO: Shouldn't the gamestate take care of rendering the GUI?
if(GUIObjectRoot) GUIObjectRoot->render();
if(fadeIn>0&&fadeIn<255){
SDL_BlitSurface(screen,NULL,tempSurface,NULL);
SDL_FillRect(screen,NULL,0);
SDL_SetAlpha(tempSurface, SDL_SRCALPHA, fadeIn);
SDL_BlitSurface(tempSurface,NULL,screen,NULL);
fadeIn+=17;
}
#ifdef RECORD_PICUTRE_SEQUENCE
if(recordPictureSequence){
char s[64];
recordPictureIndex++;
sprintf(s,"pic%08d.bmp",recordPictureIndex);
printf("Save screen to %s\n",s);
SDL_SaveBMP(screen,(getUserPath(USER_CACHE)+s).c_str());
}
#endif
//And draw the screen surface to the actual screen.
flipScreen();
if(nextState!=STATE_NULL){
fadeIn=17;
changeState();
}
int t=FPS.getTicks();
t=(1000/g_FPS)-t;
if(t>0){
SDL_Delay(t);
}
}
//close all joysticks.
inputMgr.closeAllJoysticks();
//The game has ended, save the settings just to be sure.
saveSettings();
SDL_FreeSurface(tempSurface);
clean();
//End of program.
return 0;
}
diff --git a/src/libs/tinygettext/iconv.cpp b/src/libs/tinygettext/iconv.cpp
deleted file mode 100644
index c0b8b60..0000000
--- a/src/libs/tinygettext/iconv.cpp
+++ /dev/null
@@ -1,148 +0,0 @@
-// tinygettext - A gettext replacement that works directly on .po files
-// Copyright (C) 2009 Ingo Ruhnke <grumbel@gmx.de>
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-#include <ctype.h>
-#include <assert.h>
-#include <sstream>
-#include <errno.h>
-#include <stdexcept>
-#include <string.h>
-#include <stdlib.h>
-
-#include "iconv.hpp"
-#include "log_stream.hpp"
-
-namespace tinygettext {
-
-#ifndef tinygettext_ICONV_CONST
-# define tinygettext_ICONV_CONST
-#endif
-
-IConv::IConv()
- : to_charset(),
- from_charset(),
- cd(0)
-{}
-
-IConv::IConv(const std::string& from_charset_, const std::string& to_charset_)
- : to_charset(),
- from_charset(),
- cd(0)
-{
- set_charsets(from_charset_, to_charset_);
-}
-
-IConv::~IConv()
-{
- if (cd)
- tinygettext_iconv_close(cd);
-}
-
-void
-IConv::set_charsets(const std::string& from_charset_, const std::string& to_charset_)
-{
- if (cd)
- tinygettext_iconv_close(cd);
-
- from_charset = from_charset_;
- to_charset = to_charset_;
-
- for(std::string::iterator i = to_charset.begin(); i != to_charset.end(); ++i)
- *i = static_cast<char>(toupper(*i));
-
- for(std::string::iterator i = from_charset.begin(); i != from_charset.end(); ++i)
- *i = static_cast<char>(toupper(*i));
-
- if (to_charset == from_charset)
- {
- cd = 0;
- }
- else
- {
- cd = tinygettext_iconv_open(to_charset.c_str(), from_charset.c_str());
- if (cd == reinterpret_cast<tinygettext_iconv_t>(-1))
- {
- if(errno == EINVAL)
- {
- std::ostringstream str;
- str << "IConv construction failed: conversion from '" << from_charset
- << "' to '" << to_charset << "' not available";
- throw std::runtime_error(str.str());
- }
- else
- {
- std::ostringstream str;
- str << "IConv: construction failed: " << strerror(errno);
- throw std::runtime_error(str.str());
- }
- }
- }
-}
-
-/// Convert a string from encoding to another.
-std::string
-IConv::convert(const std::string& text)
-{
- if (!cd)
- {
- return text;
- }
- else
- {
- size_t inbytesleft = text.size();
- size_t outbytesleft = 4*inbytesleft; // Worst case scenario: ASCII -> UTF-32?
-
- // We try to avoid to much copying around, so we write directly into
- // a std::string
- tinygettext_ICONV_CONST char* inbuf = const_cast<char*>(&text[0]);
- std::string result(outbytesleft, 'X');
- char* outbuf = &result[0];
-
- // Try to convert the text.
- size_t ret = tinygettext_iconv(cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft);
- if (ret == static_cast<size_t>(-1))
- {
- if (errno == EILSEQ || errno == EINVAL)
- { // invalid multibyte sequence
- tinygettext_iconv(cd, NULL, NULL, NULL, NULL); // reset state
-
- // FIXME: Could try to skip the invalid byte and continue
- log_error << "error: tinygettext:iconv: invalid multibyte sequence in: \"" << text << "\"" << std::endl;
- }
- else if (errno == E2BIG)
- { // output buffer to small
- assert(!"tinygettext/iconv.cpp: E2BIG: This should never be reached");
- }
- else if (errno == EBADF)
- {
- assert(!"tinygettext/iconv.cpp: EBADF: This should never be reached");
- }
- else
- {
- assert(!"tinygettext/iconv.cpp: <unknown>: This should never be reached");
- }
- }
-
- result.resize(4*text.size() - outbytesleft);
-
- return result;
- }
-}
-
-} // namespace tinygettext
-
-/* EOF */
diff --git a/src/libs/tinygettext/iconv.hpp b/src/libs/tinygettext/iconv.hpp
deleted file mode 100644
index 1ae1750..0000000
--- a/src/libs/tinygettext/iconv.hpp
+++ /dev/null
@@ -1,71 +0,0 @@
-// tinygettext - A gettext replacement that works directly on .po files
-// Copyright (C) 2006 Ingo Ruhnke <grumbel@gmx.de>
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-#ifndef HEADER_TINYGETTEXT_ICONV_HPP
-#define HEADER_TINYGETTEXT_ICONV_HPP
-
-#include <string>
-
-#ifdef HAVE_SDL
-# include "SDL.h"
-
-# define tinygettext_ICONV_CONST const
-# define tinygettext_iconv_t SDL_iconv_t
-# define tinygettext_iconv SDL_iconv
-# define tinygettext_iconv_open SDL_iconv_open
-# define tinygettext_iconv_close SDL_iconv_close
-#else
-# include <iconv.h>
-
-# ifdef HAVE_ICONV_CONST
-# define tinygettext_ICONV_CONST ICONV_CONST
-# else
-# define tinygettext_ICONV_CONST
-# endif
-
-# define tinygettext_iconv_t iconv_t
-# define tinygettext_iconv iconv
-# define tinygettext_iconv_open iconv_open
-# define tinygettext_iconv_close iconv_close
-#endif
-
-namespace tinygettext {
-
-class IConv
-{
-private:
- std::string to_charset;
- std::string from_charset;
- tinygettext_iconv_t cd;
-
-public:
- IConv();
- IConv(const std::string& fromcode, const std::string& tocode);
- ~IConv();
-
- void set_charsets(const std::string& fromcode, const std::string& tocode);
- std::string convert(const std::string& text);
-
-private:
- IConv (const IConv&);
- IConv& operator= (const IConv&);
-};
-
-} // namespace tinygettext
-
-#endif
-
-/* EOF */
diff --git a/src/libs/tinygettext/plural_forms.cpp b/src/libs/tinygettext/plural_forms.cpp
index 8271437..75196a7 100644
--- a/src/libs/tinygettext/plural_forms.cpp
+++ b/src/libs/tinygettext/plural_forms.cpp
@@ -1,89 +1,89 @@
// tinygettext - A gettext replacement that works directly on .po files
// Copyright (C) 2006 Ingo Ruhnke <grumbel@gmx.de>
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "plural_forms.hpp"
#include <map>
namespace tinygettext {
/**
* Plural functions are used to select a string that matches a given
* count. \a n is the count and the return value is the string index
* used in the .po file, for example:
*
* msgstr[0] = "You got %d error";
* msgstr[1] = "You got %d errors";
* ^-- return value of plural function
*/
unsigned int plural1(int ) { return 0; }
unsigned int plural2_1(int n) { return (n != 1); }
unsigned int plural2_2(int n) { return (n > 1); }
unsigned int plural2_mk(int n) { return n==1 || n%10==1 ? 0 : 1; }
unsigned int plural3_lv(int n) { return static_cast<unsigned int>(n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2); }
unsigned int plural3_ga(int n) { return static_cast<unsigned int>(n==1 ? 0 : n==2 ? 1 : 2); }
unsigned int plural3_lt(int n) { return static_cast<unsigned int>(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2); }
unsigned int plural3_1(int n) { return static_cast<unsigned int>(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2); }
unsigned int plural3_sk(int n) { return static_cast<unsigned int>( (n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2 ); }
unsigned int plural3_pl(int n) { return static_cast<unsigned int>(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2); }
unsigned int plural3_sl(int n) { return static_cast<unsigned int>(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3); }
unsigned int plural4_ar(int n) { return static_cast<unsigned int>( n==1 ? 0 : n==2 ? 1 : n>=3 && n<=10 ? 2 : 3 ); }
PluralForms
PluralForms::from_string(const std::string& str)
{
- static std::map<std::string, struct PluralForms> plural_forms;
+ static std::map<std::string, PluralForms> plural_forms;
if (plural_forms.empty())
{
// Note that the plural forms here shouldn't contain any spaces
plural_forms["Plural-Forms:nplurals=1;plural=0;"] = PluralForms(1, plural1);
plural_forms["Plural-Forms:nplurals=2;plural=(n!=1);"] = PluralForms(2, plural2_1);
plural_forms["Plural-Forms:nplurals=2;plural=n!=1;"] = PluralForms(2, plural2_1);
plural_forms["Plural-Forms:nplurals=2;plural=(n>1);"] = PluralForms(2, plural2_2);
plural_forms["Plural-Forms:nplurals=2;plural=n==1||n%10==1?0:1;"] = PluralForms(2, plural2_mk);
plural_forms["Plural-Forms:nplurals=3;plural=n%10==1&&n%100!=11?0:n!=0?1:2);"] = PluralForms(2, plural3_lv);
plural_forms["Plural-Forms:nplurals=3;plural=n==1?0:n==2?1:2;"] = PluralForms(3, plural3_ga);
plural_forms["Plural-Forms:nplurals=3;plural=(n%10==1&&n%100!=11?0:n%10>=2&&(n%100<10||n%100>=20)?1:2);"] = PluralForms(3, plural3_lt);
plural_forms["Plural-Forms:nplurals=3;plural=(n%10==1&&n%100!=11?0:n%10>=2&&n%10<=4&&(n%100<10||n%100>=20)?1:2);"] = PluralForms(3, plural3_1);
plural_forms["Plural-Forms:nplurals=3;plural=(n==1)?0:(n>=2&&n<=4)?1:2;"] = PluralForms(3, plural3_sk);
plural_forms["Plural-Forms:nplurals=3;plural=(n==1?0:n%10>=2&&n%10<=4&&(n%100<10||n%100>=20)?1:2);"] = PluralForms(3, plural3_pl);
plural_forms["Plural-Forms:nplurals=3;plural=(n%100==1?0:n%100==2?1:n%100==3||n%100==4?2:3);"] = PluralForms(3, plural3_sl);
plural_forms["Plural-Forms:nplurals=4;plural=n==1?0:n==2?1:n>=3&&n<=10?2:3;"]=PluralForms(4, plural4_ar);
}
// Remove spaces from string before lookup
std::string space_less_str;
for(std::string::size_type i = 0; i < str.size(); ++i)
if (!isspace(str[i]))
space_less_str += str[i];
- std::map<std::string, struct PluralForms>::const_iterator it= plural_forms.find(space_less_str);
+ std::map<std::string, PluralForms>::const_iterator it= plural_forms.find(space_less_str);
if (it != plural_forms.end())
{
return it->second;
}
else
{
return PluralForms();
}
}
} // namespace tinygettext
/* EOF */
diff --git a/src/libs/tinygettext/po_parser.cpp b/src/libs/tinygettext/po_parser.cpp
index 5ceb3fd..a56b1b4 100644
--- a/src/libs/tinygettext/po_parser.cpp
+++ b/src/libs/tinygettext/po_parser.cpp
@@ -1,496 +1,495 @@
// tinygettext - A gettext replacement that works directly on .po files
// Copyright (C) 2009 Ingo Ruhnke <grumbel@gmx.de>
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "po_parser.hpp"
#include <iostream>
#include <ctype.h>
#include <string>
#include <istream>
#include <string.h>
#include <map>
#include <stdlib.h>
#include "language.hpp"
#include "log_stream.hpp"
-#include "iconv.hpp"
#include "dictionary.hpp"
#include "plural_forms.hpp"
namespace tinygettext {
bool POParser::pedantic = true;
void
POParser::parse(const std::string& filename, std::istream& in, Dictionary& dict)
{
POParser parser(filename, in, dict);
parser.parse();
}
class POParserError {};
POParser::POParser(const std::string& filename_, std::istream& in_, Dictionary& dict_, bool use_fuzzy_) :
filename(filename_),
in(in_),
dict(dict_),
use_fuzzy(use_fuzzy_),
running(false),
eof(false),
big5(false),
line_number(0),
- current_line(),
- conv()
+ current_line()//,
+ //conv()
{
}
POParser::~POParser()
{
}
void
POParser::warning(const std::string& msg)
{
log_warning << filename << ":" << line_number << ": warning: " << msg << ": " << current_line << std::endl;
//log_warning << "Line: " << current_line << std::endl;
}
void
POParser::error(const std::string& msg)
{
log_error << filename << ":" << line_number << ": error: " << msg << ": " << current_line << std::endl;
// Try to recover from an error by searching for start of another entry
do
next_line();
while(!eof && !is_empty_line());
throw POParserError();
}
void
POParser::next_line()
{
line_number += 1;
if (!std::getline(in, current_line))
eof = true;
}
void
POParser::get_string_line(std::ostringstream& out,unsigned int skip)
{
if (skip+1 >= static_cast<unsigned int>(current_line.size()))
error("unexpected end of line");
if (current_line[skip] != '"')
error("expected start of string '\"'");
std::string::size_type i;
for(i = skip+1; current_line[i] != '\"'; ++i)
{
if (big5 && static_cast<unsigned char>(current_line[i]) >= 0x81 && static_cast<unsigned char>(current_line[i]) <= 0xfe)
{
out << current_line[i];
i += 1;
if (i >= current_line.size())
error("invalid big5 encoding");
out << current_line[i];
}
else if (i >= current_line.size())
{
error("unexpected end of string");
}
else if (current_line[i] == '\\')
{
i += 1;
if (i >= current_line.size())
error("unexpected end of string in handling '\\'");
switch (current_line[i])
{
case 'a': out << '\a'; break;
case 'b': out << '\b'; break;
case 'v': out << '\v'; break;
case 'n': out << '\n'; break;
case 't': out << '\t'; break;
case 'r': out << '\r'; break;
case '"': out << '"'; break;
case '\\': out << '\\'; break;
default:
std::ostringstream err;
err << "unhandled escape '\\" << current_line[i] << "'";
warning(err.str());
out << current_line[i-1] << current_line[i];
break;
}
}
else
{
out << current_line[i];
}
}
// process trailing garbage in line and warn if there is any
for(i = i+1; i < current_line.size(); ++i)
if (!isspace(current_line[i]))
{
warning("unexpected garbage after string ignoren");
break;
}
}
std::string
POParser::get_string(unsigned int skip)
{
std::ostringstream out;
if (skip+1 >= static_cast<unsigned int>(current_line.size()))
error("unexpected end of line");
if (current_line[skip] == ' ' && current_line[skip+1] == '"')
{
get_string_line(out, skip+1);
}
else
{
if (pedantic)
warning("keyword and string must be seperated by a single space");
for(;;)
{
if (skip >= static_cast<unsigned int>(current_line.size()))
error("unexpected end of line");
else if (current_line[skip] == '\"')
{
get_string_line(out, skip);
break;
}
else if (!isspace(current_line[skip]))
{
error("string must start with '\"'");
}
else
{
// skip space
}
skip += 1;
}
}
next:
next_line();
for(std::string::size_type i = 0; i < current_line.size(); ++i)
{
if (current_line[i] == '"')
{
if (i == 1)
if (pedantic)
warning("leading whitespace before string");
get_string_line(out, i);
goto next;
}
else if (isspace(current_line[i]))
{
// skip
}
else
{
break;
}
}
return out.str();
}
static bool has_prefix(const std::string& lhs, const std::string rhs)
{
if (lhs.length() < rhs.length())
return false;
else
return lhs.compare(0, rhs.length(), rhs) == 0;
}
void
POParser::parse_header(const std::string& header)
{
std::string from_charset;
std::string::size_type start = 0;
for(std::string::size_type i = 0; i < header.length(); ++i)
{
if (header[i] == '\n')
{
std::string line = header.substr(start, i - start);
if (has_prefix(line, "Content-Type:"))
{
// from_charset = line.substr(len);
unsigned int len = strlen("Content-Type: text/plain; charset=");
if (line.compare(0, len, "Content-Type: text/plain; charset=") == 0)
{
from_charset = line.substr(len);
for(std::string::iterator ch = from_charset.begin(); ch != from_charset.end(); ++ch)
*ch = static_cast<char>(toupper(*ch));
}
else
{
warning("malformed Content-Type header");
}
}
else if (has_prefix(line, "Plural-Forms:"))
{
PluralForms plural_forms = PluralForms::from_string(line);
if (!plural_forms)
{
warning("unknown Plural-Forms given");
}
else
{
if (!dict.get_plural_forms())
{
dict.set_plural_forms(plural_forms);
}
else
{
if (dict.get_plural_forms() != plural_forms)
{
warning("Plural-Forms missmatch between .po file and dictionary");
}
}
}
}
start = i+1;
}
}
if (from_charset.empty() || from_charset == "CHARSET")
{
warning("charset not specified for .po, fallback to utf-8");
from_charset = "UTF-8";
}
else if (from_charset == "BIG5")
{
big5 = true;
}
- conv.set_charsets(from_charset, dict.get_charset());
+ //conv.set_charsets(from_charset, dict.get_charset());
}
bool
POParser::is_empty_line()
{
if (current_line.empty())
{
return true;
}
else if (current_line[0] == '#')
{ // handle comments as empty lines
if (current_line.size() == 1 || (current_line.size() >= 2 && isspace(current_line[1])))
return true;
else
return false;
}
else
{
for(std::string::iterator i = current_line.begin(); i != current_line.end(); ++i)
{
if (!isspace(*i))
return false;
}
}
return true;
}
bool
POParser::prefix(const char* prefix_str)
{
return current_line.compare(0, strlen(prefix_str), prefix_str) == 0;
}
void
POParser::parse()
{
next_line();
// skip UTF-8 intro that some text editors produce
// see http://en.wikipedia.org/wiki/Byte-order_mark
if (current_line.size() >= 3 &&
- current_line[0] == static_cast<char>(0xef) &&
- current_line[1] == static_cast<char>(0xbb) &&
- current_line[2] == static_cast<char>(0xbf))
+ current_line[0] == static_cast<unsigned char>(0xef) &&
+ current_line[1] == static_cast<unsigned char>(0xbb) &&
+ current_line[2] == static_cast<unsigned char>(0xbf))
{
current_line = current_line.substr(3);
}
// Parser structure
while(!eof)
{
try
{
bool fuzzy = false;
bool has_msgctxt = false;
std::string msgctxt;
std::string msgid;
while(prefix("#"))
{
if (current_line.size() >= 2 && current_line[1] == ',')
{
// FIXME: Rather simplistic hunt for fuzzy flag
if (current_line.find("fuzzy", 2) != std::string::npos)
fuzzy = true;
}
next_line();
}
if (!is_empty_line())
{
if (prefix("msgctxt"))
{
has_msgctxt = true;
msgctxt = get_string(7);
}
if (prefix("msgid"))
msgid = get_string(5);
else
error("expected 'msgid'");
if (prefix("msgid_plural"))
{
std::string msgid_plural = get_string(12);
std::vector<std::string> msgstr_num;
bool saw_nonempty_msgstr = false;
next:
if (is_empty_line())
{
if (msgstr_num.empty())
error("expected 'msgstr[N] (0 <= N <= 9)'");
}
else if (prefix("msgstr[") &&
current_line.size() > 8 &&
isdigit(current_line[7]) && current_line[8] == ']')
{
unsigned int number = static_cast<unsigned int>(current_line[7] - '0');
std::string msgstr = get_string(9);
if(!msgstr.empty())
saw_nonempty_msgstr = true;
if (number >= msgstr_num.size())
msgstr_num.resize(number+1);
- msgstr_num[number] = conv.convert(msgstr);
+ msgstr_num[number] = msgstr; //conv.convert(msgstr);
goto next;
}
else
{
error("expected 'msgstr[N]'");
}
if (!is_empty_line())
error("expected 'msgstr[N]' or empty line");
if (saw_nonempty_msgstr)
{
if (use_fuzzy || !fuzzy)
{
if (!dict.get_plural_forms())
{
warning("msgstr[N] seen, but no Plural-Forms given");
}
else
{
if (msgstr_num.size() != dict.get_plural_forms().get_nplural())
{
warning("msgstr[N] count doesn't match Plural-Forms.nplural");
}
}
if (has_msgctxt)
dict.add_translation(msgctxt, msgid, msgid_plural, msgstr_num);
else
dict.add_translation(msgid, msgid_plural, msgstr_num);
}
if (0)
{
std::cout << (fuzzy?"fuzzy":"not-fuzzy") << std::endl;
std::cout << "msgid \"" << msgid << "\"" << std::endl;
std::cout << "msgid_plural \"" << msgid_plural << "\"" << std::endl;
for(std::vector<std::string>::size_type i = 0; i < msgstr_num.size(); ++i)
- std::cout << "msgstr[" << i << "] \"" << conv.convert(msgstr_num[i]) << "\"" << std::endl;
+ std::cout << "msgstr[" << i << "] \"" << msgstr_num[i] /*conv.convert(msgstr_num[i])*/ << "\"" << std::endl;
std::cout << std::endl;
}
}
}
else if (prefix("msgstr"))
{
std::string msgstr = get_string(6);
if (msgid.empty())
{
parse_header(msgstr);
}
else if(!msgstr.empty())
{
if (use_fuzzy || !fuzzy)
{
if (has_msgctxt)
- dict.add_translation(msgctxt, msgid, conv.convert(msgstr));
+ dict.add_translation(msgctxt, msgid, msgstr /*conv.convert(msgstr)*/);
else
- dict.add_translation(msgid, conv.convert(msgstr));
+ dict.add_translation(msgid, msgstr /*conv.convert(msgstr)*/);
}
if (0)
{
std::cout << (fuzzy?"fuzzy":"not-fuzzy") << std::endl;
std::cout << "msgid \"" << msgid << "\"" << std::endl;
- std::cout << "msgstr \"" << conv.convert(msgstr) << "\"" << std::endl;
+ std::cout << "msgstr \"" << msgstr /*conv.convert(msgstr)*/ << "\"" << std::endl;
std::cout << std::endl;
}
}
}
else
{
error("expected 'msgstr' or 'msgid_plural'");
}
}
if (!is_empty_line())
error("expected empty line");
next_line();
}
catch(POParserError&)
{
}
}
}
} // namespace tinygettext
/* EOF */
diff --git a/src/libs/tinygettext/po_parser.hpp b/src/libs/tinygettext/po_parser.hpp
index 329af59..c3c4513 100644
--- a/src/libs/tinygettext/po_parser.hpp
+++ b/src/libs/tinygettext/po_parser.hpp
@@ -1,75 +1,80 @@
// tinygettext - A gettext replacement that works directly on .po files
// Copyright (C) 2009 Ingo Ruhnke <grumbel@gmx.de>
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifndef HEADER_TINYGETTEXT_PO_PARSER_HPP
#define HEADER_TINYGETTEXT_PO_PARSER_HPP
#include <iosfwd>
+#include <string>
-#include "iconv.hpp"
+//#include "iconv.hpp"
namespace tinygettext {
class Dictionary;
class POParser
{
private:
std::string filename;
std::istream& in;
Dictionary& dict;
bool use_fuzzy;
bool running;
bool eof;
bool big5;
int line_number;
std::string current_line;
- IConv conv;
+ //IConv conv;
POParser(const std::string& filename, std::istream& in_, Dictionary& dict_, bool use_fuzzy = true);
~POParser();
void parse_header(const std::string& header);
void parse();
void next_line();
std::string get_string(unsigned int skip);
void get_string_line(std::ostringstream& str,unsigned int skip);
bool is_empty_line();
bool prefix(const char* );
+#ifdef WIN32
+ void error(const std::string& msg);
+#else
void error(const std::string& msg) __attribute__((__noreturn__));
+#endif
void warning(const std::string& msg);
public:
/** @param filename name of the istream, only used in error messages
@param in stream from which the PO file is read.
@param dict dictionary to which the strings are written */
static void parse(const std::string& filename, std::istream& in, Dictionary& dict);
static bool pedantic;
private:
POParser (const POParser&);
POParser& operator= (const POParser&);
};
} // namespace tinygettext
#endif
/* EOF */

File Metadata

Mime Type
text/x-diff
Expires
Tue, Jun 16, 12:15 AM (2 w, 2 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
71220
Default Alt Text
(106 KB)

Event Timeline