Page Menu
Home
Phabricator (Chris)
Search
Configure Global Search
Log In
Files
F131508
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
106 KB
Referenced Files
None
Subscribers
None
View Options
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
Details
Attached
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)
Attached To
Mode
R79 meandmyshadow
Attached
Detach File
Event Timeline