diff --git a/crescendo/SimpleAvZ/README.md b/crescendo/SimpleAvZ/README.md index ddf3308..34d5de0 100644 --- a/crescendo/SimpleAvZ/README.md +++ b/crescendo/SimpleAvZ/README.md @@ -339,11 +339,12 @@ C(400, until(1036), ...); // 1036cs铲 RM(400, SUNFLOWER); // 于400cs铲除场地上所有小向 RM(400, PUMPKIN, 1, 1); // 铲除1-1南瓜(没有则不铲) RM(400, 1, 1); // 铲除1-1, 优先铲除非南瓜 +RM(400, {{1, 1}, {1, 2}}); // 铲除1-1和1-2, 优先铲除非南瓜 RM(400, {1, 2, 5, 6}, 9); // 铲除1,2,5,6路9列, 优先铲除非南瓜 RM(after(751), ...); // 用法同上, 延迟751cs生效 ``` -铲除植物. 可提供单一坐标, 多行同列. 也可指定要铲除的植物种类. +铲除植物. 可提供单一坐标, 多个坐标, 多行同列. 也可指定要铲除的植物种类. ### 演示功能 diff --git a/crescendo/SimpleAvZ/SimpleAvZ/cannon.h b/crescendo/SimpleAvZ/SimpleAvZ/cannon.h index ae1ce4c..5d828bf 100644 --- a/crescendo/SimpleAvZ/SimpleAvZ/cannon.h +++ b/crescendo/SimpleAvZ/SimpleAvZ/cannon.h @@ -8,18 +8,18 @@ class CobOperator : public AvZ::PaoOperator { public: - // Create CobOperator and specify cobs with tail at which cols to use. - // *** Usage: - // CobOperator c1(1)--------- Only use cobs with tail at col 1 - // CobOperator c45(4, 5)----- Only use cobs with tail at col 4 or 5 + // 创建 CobOperator. 指定要用炮尾在哪些列的炮. + // *** 使用示例: + // CobOperator c1(1)---------只用炮尾在1列的炮 + // CobOperator c45(4, 5)-----只用炮尾在4或5列的炮 template CobOperator(Args... args) : AvZ::PaoOperator() { for (int col : {args...}) { - validate_cob_col(col, "CobOperator constructor"); + validate_cob_col(col, "CobOperator 构造函数"); if (cob_cols.count(col)) { - _SimpleAvZInternal::error("CobOperator constructor", "Duplicate cob tail cols: #", col); + _SimpleAvZInternal::error("CobOperator 构造函数", "不可重复指定炮尾列\n重复的炮尾列: #", col); } cob_cols.insert(col); } @@ -30,15 +30,14 @@ class CobOperator : public AvZ::PaoOperator { { } - // Fire two cobs. - // If rows are omitted, they default to row 2 & 5 for PE/FE and row 2 & 4 for other scenes. - // If col is omitted, it defaults to 9. - // *** Usage: - // c.PP(318)----------------- Fire (2,9) and (5,9), taking effect at 318cs - // c.PP(318, 8)-------------- Fire (2,8) and (5,8) - // c.PP(318, {8, 9})--------- Fire (2,8) and (5,9) - // c.PP(318, {2, 6}, 9)------ Fire (2,9) and (6,9) - // c.PP(after(110), ...)----- Take effect after 110cs + // 发射一组并炸炮. + // 若省略行数, 默认六行场地炸 2,5 路, 五行场地炸 2,4 路. 若省略列数, 默认炸 9 列. + // *** 使用示例: + // c.PP(318)-----------------炸(2,9)与(5,9), 318cs生效 + // c.PP(318, 8)--------------炸(2,8)与(5,8) + // c.PP(318, {8, 9})---------炸(2,8)与(5,9) + // c.PP(318, {2, 6}, 9)------炸(2,9)与(6,9) + // c.PP(after(110), ...)-----用法同上, 延迟110cs生效 void PP(Time time, const std::array& rows, float col) { cob_internal(time, {{rows[0], col}, {rows[1], col}}, "PP"); @@ -60,15 +59,14 @@ class CobOperator : public AvZ::PaoOperator { PP(time, {9, 9}); } - // Fire two interception cobs. - // If rows are omitted, they default to row 1 & 5 for PE/FE and row 1 & 4 for other scenes. - // If col is omitted, it defaults to 9. - // *** Usage: - // c.DD(318)----------------- Fire (1,9) and (5,9), taking effect at 318cs - // c.DD(318, 8)-------------- Fire (1,8) and (5,8) - // c.DD(318, {8, 9})--------- Fire (1,8) and (5,9) - // c.DD(318, {2, 5}, 3.5)---- Fire (2,3.5) and (5,3.5) - // c.DD(after(110), ...)----- Take effect after 110cs + // 发射一组拦截炮. + // 若省略行数, 六行场地炸 1,5 路, 五行场地炸 1,4 路. 若省略列数, 默认炸 9 列. + // *** 使用示例: + // c.DD(318)-----------------炸(1,9)与(5,9), 318cs生效 + // c.DD(318, 8)--------------炸(1,8)与(5,8) + // c.DD(318, {8, 9})---------炸(1,8)与(5,9) + // c.DD(318, {2, 5}, 3.5)----炸(2,3.5)与(5,3.5) + // c.DD(after(110), ...)-----用法同上, 延迟110cs生效 void DD(Time time, const std::array& rows, float col) { std::vector positions; @@ -93,12 +91,11 @@ class CobOperator : public AvZ::PaoOperator { DD(time, {9, 9}); } - // Fire one cob. - // You may specify which cob to use. - // *** Usage: - // c.P(318, 2, 9)----------------- Fire (2,9), taking effect at 318cs - // c.P(318, 1, 1, 2, 8)----------- Use cob at 1-1 to fire (2,8) - // c.P(after(110), ...)----------- Take effect after 110cs + // 发射一门炮. 可指明要用哪门炮. + // *** 使用示例: + // c.P(318, 2, 9)-----------------炸(2,9), 318cs生效 + // c.P(318, 1, 1, 2, 8)-----------使用1-1炮炸(2,8) + // c.P(after(110), ...)-----------用法同上, 延迟110cs生效 void P(Time time, int row, float col) { cob_internal(time, {{row, col}}, "P"); @@ -109,26 +106,26 @@ class CobOperator : public AvZ::PaoOperator { cob_internal(time, {{row, col}}, "P", {cob_row, cob_col}); } - // Fire one separation cob. - // *** Usage: - // c.B(304, 5, 8.225)----- Fire (5, 8.225), taking effect at 304cs + // 发射分离炮. + // *** 使用示例: + // c.B(304, 5, 8.225)-----炸(5, 8.225), 304cs生效 void B(Time time, int row, float col) { cob_internal(time, {{row, col}}, "B"); } - // Fire one interception cob. - // *** Usage: - // c.D(395, 1, 9)----- Fire (1,9), taking effect at 395cs + // 发射拦截炮. + // *** 使用示例: + // c.D(395, 1, 9)-----炸(1,9), 395cs生效 void D(Time time, int row, float col) { cob_internal(time, {{row, col}}, "D"); } - // Exclude certain cobs from being used. - // *** Usage: - // c.ExcludeCob(3, 5)--------- Do not use cob at 3-5, effective since game start [EXT] - // c.ExcludeCob(400, ...)----- Effective since 400cs + // 不使用特定炮. + // *** 使用用例: + // c.ExcludeCob(3, 5)---------不使用3-5炮, 游戏开始时起效[外] + // c.ExcludeCob(400, ...)-----400cs起效 void ExcludeCob(Time time, int row, int col) { _SimpleAvZInternal::get_effect_time_and_set_time(time, "ExcludeCob"); @@ -141,9 +138,9 @@ class CobOperator : public AvZ::PaoOperator { exclude_cob_internal(row, col); } - // Reset to use all cobs. - // *** Usage: - // c.ResetCob(400)----- Reset to use all cobs, effective since 400cs + // 重置为使用所有炮. + // *** 使用用例: + // c.ResetCob(400)-----重置为使用所有炮, 400cs起效 void ResetCob(Time time) { _SimpleAvZInternal::get_effect_time_and_set_time(time, "ResetCob"); @@ -173,14 +170,14 @@ class CobOperator : public AvZ::PaoOperator { { int max_row = _SimpleAvZInternal::is_visually_six_rows() ? 6 : 5; if (row < 1 || row > max_row) { - _SimpleAvZInternal::error(func_name, "Cob row should be within 1~#: #", max_row, row); + _SimpleAvZInternal::error(func_name, "炮行数应在1~#内\n炮行数: #", max_row, row); } } void validate_cob_col(int col, const std::string& func_name) { if (col < 1 || col > 8) { - _SimpleAvZInternal::error(func_name, "Cob col should be within 1~8: #", col); + _SimpleAvZInternal::error(func_name, "炮尾列应在1~8内\n炮尾列: #", col); } } @@ -207,10 +204,10 @@ class CobOperator : public AvZ::PaoOperator { for (const auto& pos : positions) { if (pos.row < 1 || pos.row > max_row) { - _SimpleAvZInternal::error(func_name, "Cob hit row should be within 1~#: #", max_row, pos.row); + _SimpleAvZInternal::error(func_name, "落点行应在1~#内\n落点行: #", max_row, pos.row); } if (pos.col < 0 || pos.col > 10) { - _SimpleAvZInternal::error(func_name, "Cob hit col should be within 0.0~10.0: #", pos.col); + _SimpleAvZInternal::error(func_name, "落点列应在0.0~10.0内\n落点列: #", pos.col); } } @@ -274,15 +271,14 @@ class CobOperator : public AvZ::PaoOperator { CobOperator cob_operator; -// Fire two cobs. -// If rows are omitted, they default to row 2 & 5 for PE/FE and row 2 & 4 for other scenes. -// If col is omitted, it defaults to 9. -// *** Usage: -// PP(318)----------------- Fire (2,9) and (5,9), taking effect at 318cs -// PP(318, 8)-------------- Fire (2,8) and (5,8) -// PP(318, {8, 9})--------- Fire (2,8) and (5,9) -// PP(318, {2, 6}, 9)------ Fire (2,9) and (6,9) -// PP(after(110), ...)----- Take effect after 110cs +// 发射一组并炸炮. +// 若省略行数, 默认六行场地炸 2,5 路, 五行场地炸 2,4 路. 若省略列数, 默认炸 9 列. +// *** 使用示例: +// PP(318)-----------------炸(2,9)与(5,9), 318cs生效 +// PP(318, 8)--------------炸(2,8)与(5,8) +// PP(318, {8, 9})---------炸(2,8)与(5,9) +// PP(318, {2, 6}, 9)------炸(2,9)与(6,9) +// PP(after(110), ...)-----用法同上, 延迟110cs生效 void PP(Time time, const std::array& rows, float col) { cob_operator.PP(time, rows, col); @@ -303,15 +299,14 @@ void PP(Time time) cob_operator.PP(time); } -// Fire two interception cobs. -// If rows are omitted, they default to row 1 & 5 for PE/FE and row 1 & 4 for other scenes. -// If col is omitted, it defaults to 9. -// *** Usage: -// DD(318)----------------- Fire (1,9) and (5,9), taking effect at 318cs -// DD(318, 8)-------------- Fire (1,8) and (5,8) -// DD(318, {8, 9})--------- Fire (1,8) and (5,9) -// DD(318, {2, 5}, 3.5)---- Fire (2,3.5) and (5,3.5) -// DD(after(110), ...)----- Take effect after 110cs +// 发射一组拦截炮. +// 若省略行数, 六行场地炸 1,5 路, 五行场地炸 1,4 路. 若省略列数, 默认炸 9 列. +// *** 使用示例: +// DD(318)-----------------炸(1,9)与(5,9), 318cs生效 +// DD(318, 8)--------------炸(1,8)与(5,8) +// DD(318, {8, 9})---------炸(1,8)与(5,9) +// PP(318, {2, 5}, 3.5)----炸(2,3.5)与(5,3.5) +// DD(after(110), ...)-----用法同上, 延迟110cs生效 void DD(Time time, const std::array& rows, float col) { cob_operator.DD(time, rows, col); @@ -332,12 +327,11 @@ void DD(Time time) cob_operator.DD(time); } -// Fire one cob. -// You may specify which cob to use. -// *** Usage: -// P(318, 2, 9)----------------- Fire (2,9), taking effect at 318cs -// P(318, 1, 1, 2, 8)----------- Use cob at 1-1 to fire (2,8) -// P(after(110), ...)----------- Take effect after 110cs +// 发射一门炮. 可指明要用哪门炮. +// *** 使用示例: +// P(318, 2, 9)-----------------炸(2,9), 318cs生效 +// P(318, 1, 1, 2, 8)-----------使用1-1炮炸(2,8) +// P(after(110), ...)-----------用法同上, 延迟110cs生效 void P(Time time, int row, float col) { cob_operator.P(time, row, col); @@ -348,26 +342,26 @@ void P(Time time, int cob_row, int cob_col, int row, float col) cob_operator.P(time, cob_row, cob_col, row, col); } -// Fire one separation cob. -// *** Usage: -// B(304, 5, 8.225)----- Fire (5, 8.225), taking effect at 304cs +// 发射分离炮. +// *** 使用示例: +// B(304, 5, 8.225)-----炸(5, 8.225), 304cs生效 void B(Time time, int row, float col) { cob_operator.B(time, row, col); } -// Fire one interception cob. -// *** Usage: -// D(395, 1, 9)----- Fire (1,9), taking effect at 395cs +// 发射拦截炮. +// *** 使用示例: +// D(395, 1, 9)-----炸(1,9), 395cs生效 void D(Time time, int row, float col) { cob_operator.D(time, row, col); } -// Exclude certain cobs from being used. -// *** Usage: -// ExcludeCob(3, 5)--------- Do not use cob at 3-5, effective since game start [EXT] -// ExcludeCob(400, ...)----- Effective since 400cs +// 不使用特定炮. +// *** 使用用例: +// ExcludeCob(3, 5)---------不使用3-5炮, 游戏开始时起效[外] +// ExcludeCob(400, ...)-----400cs起效 void ExcludeCob(Time time, int row, int col) { cob_operator.ExcludeCob(time, row, col); @@ -378,9 +372,9 @@ void ExcludeCob(int row, int col) cob_operator.ExcludeCob(row, col); } -// Reset to use all cobs. -// *** Usage: -// ResetCob(400)----- Reset to use all cobs, effective since 400cs +// 重置为使用所有炮. +// *** 使用用例: +// ResetCob(400)-----重置为使用所有炮, 400cs起效 void ResetCob(Time time) { cob_operator.ResetCob(time); diff --git a/crescendo/SimpleAvZ/SimpleAvZ/card.h b/crescendo/SimpleAvZ/SimpleAvZ/card.h index 9ddd529..66dda91 100644 --- a/crescendo/SimpleAvZ/SimpleAvZ/card.h +++ b/crescendo/SimpleAvZ/SimpleAvZ/card.h @@ -180,7 +180,7 @@ std::set get_invalid_plants(int row, const std::string& func_name) case 5: return {GRAVE_BUSTER, LILY_PAD, TANGLE_KELP, SPIKEWEED, SEA_SHROOM, COFFEE_BEAN, CATTAIL, SPIKEROCK}; default: - error(func_name, "Unknown scene: #", AvZ::GetMainObject()->scene()); + error(func_name, "不支持的场景: #", AvZ::GetMainObject()->scene()); return {}; } } @@ -189,13 +189,13 @@ void validate_card_position(const PlantType& plant_type, int row, int col, const { int max_row = is_visually_six_rows() ? 6 : 5; if (row < 1 || row > max_row) { - error(func_name, "Card row should be within 1~#: #", max_row, row); + error(func_name, "用卡行应在1~#内\n用卡行: #", max_row, row); } if (col < 1 || col > 9) { - error(func_name, "Card col should be within 1~9: #", col); + error(func_name, "用卡列应在1~9内\n用卡列: #", col); } if (get_invalid_plants(row, func_name).count(non_imitater(plant_type))) { - error(func_name, "Cannot use this card in the current scene\nCard: #\nCard row: #", non_imitater(plant_type), row); + error(func_name, "当前场景不可在此行使用此卡片\n卡片: #\n用卡行: #", non_imitater(plant_type), row); } } @@ -203,28 +203,28 @@ void validate_shovel_position(int row, int col, const std::string& func_name) { int max_row = is_visually_six_rows() ? 6 : 5; if (row < 1 || row > max_row) { - error(func_name, "Shovel row should be within 1~#: #", max_row, row); + error(func_name, "铲除行应在1~#内\n铲除行: #", max_row, row); } if (col < 1 || col > 9) { - error(func_name, "Shovel col should be within 1~9: #", col); + error(func_name, "铲除列应在1~9内\n铲除列: #", col); } } } // namespace _SimpleAvZInternal -// Shovel plants. -// You may provide a single position, multiple rows with the same column, or a certain plant type to be shoveled. -// *** Usage: -// RM(400, SUNFLOWER)----------- Shovel all sunflowers at 400cs -// RM(400, PUMPKIN, 1, 1)------- Shovel pumpkin at 1-1 (if there is no pumpkin, do nothing) -// RM(400, 1, 1)---------------- Shovel 1-1 (non-pumpkin plants first) -// RM(400, {1, 2, 5, 6}, 9)----- Shovel 1-9, 2-9, 5-9, 6-9 (non-pumpkin plants first) -// RM(after(751), ...)---------- Same usage, taking effect after 751cs +// 铲除植物. 可提供单一坐标, 多行同列. 也可指定要铲除的植物种类. +// *** 使用示例: +// RM(400, SUNFLOWER)-----------于400cs铲除场地上所有小向 +// RM(400, PUMPKIN, 1, 1)-------铲除1-1南瓜(没有则不铲) +// RM(400, 1, 1)----------------铲除1-1, 优先铲除非南瓜 +// RM(400, {{1, 1}, {1, 2}})----铲除1-1和1-2, 优先铲除非南瓜 +// RM(400, {1, 2, 5, 6}, 9)-----铲除1,2,5,6路9列, 优先铲除非南瓜 +// RM(after(751), ...)----------用法同上, 延迟751cs生效 void RM(Time time, PlantType target) { target = _SimpleAvZInternal::non_imitater(target); if (target == GRAVE_BUSTER) { - _SimpleAvZInternal::error("RM", "Cannot shovel grave buster"); + _SimpleAvZInternal::error("RM", "墓碑吞噬者无法铲除"); } _SimpleAvZInternal::get_effect_time_and_set_time(time, "RM"); @@ -243,7 +243,7 @@ void RM(Time time, PlantType target, int row, int col) target = _SimpleAvZInternal::non_imitater(target); if (target == GRAVE_BUSTER) { - _SimpleAvZInternal::error("RM", "Cannot shovel grave buster"); + _SimpleAvZInternal::error("RM", "墓碑吞噬者无法铲除"); } _SimpleAvZInternal::validate_shovel_position(row, col, "RM"); @@ -293,16 +293,16 @@ void RM(Time time, int row, int col) RM(time, {{row, col}}); } -// Use ice in nighttime. Effect time is auto-corrected. -// If effect time is not specified, it defaults to 601cs of the current wave (perfect ice for next wave). -// *** Usage: -// I(1, 2)------------------ Place ice at 1-2, taking effect at 601cs (perfect ice) -// I(after(210), 1, 2)------ Use ice, takeing effect after 210cs (ice3), recommended to be used after activation cobs -// I(359, 1, 2)------------- Use ice, taking effect at 359cs +// 夜间用原版冰. 自带生效时机修正. +// 若不指定生效时间, 默认在本波 601cs 生效. +// *** 使用示例: +// I(1, 2)------------------于1-2放置原版冰, 601cs生效(完美预判冰) +// I(after(210), 1, 2)------延迟210cs生效(ice3), 推荐在激活炮后使用 +// I(359, 1, 2)-------------359cs生效 void I(Time time, int row, int col) { if (!_SimpleAvZInternal::is_night_time()) { - _SimpleAvZInternal::error("I", "Cannot use nighttime version of I() at daytime\nThere is no need to provide ice position"); + _SimpleAvZInternal::error("I", "不可在白昼使用夜间版本的I()\n无需提供用冰位置"); } _SimpleAvZInternal::validate_card_position(ICE_SHROOM, row, col, "I"); @@ -316,16 +316,16 @@ void I(int row, int col) I(601, row, col); } -// Use imitater ice in nighttime. Effect time is auto-corrected. -// If effect time is not specified, it defaults to 601cs of the current wave (perfect ice for next wave). -// *** Usage: -// M_I(1, 2)------------------ Place imitater ice at 1-2, taking effect at 601cs (perfect ice) -// M_I(after(210), 1, 2)------ Use imitater ice, takeing effect after 210cs (ice3), recommended to be used after activation cobs -// M_I(359, 1, 2)------------- Use imitater ice, taking effect at 359cs +// 夜间用复制冰. 自带生效时机修正. +// 若不指定生效时间, 默认在本波 601cs 生效. +// *** 使用示例: +// M_I(1, 2)------------------于1-2放置复制冰, 601cs生效(完美预判冰) +// M_I(after(210), 1, 2)------延迟210cs生效(ice3), 推荐在激活炮后使用 +// M_I(359, 1, 2)-------------359cs生效 void M_I(Time time, int row, int col) { if (!_SimpleAvZInternal::is_night_time()) { - _SimpleAvZInternal::error("M_I", "M_I is for nighttime only"); + _SimpleAvZInternal::error("M_I", "M_I为夜间复制冰函数, 不可在白昼使用"); } _SimpleAvZInternal::validate_card_position(M_ICE_SHROOM, row, col, "M_I"); @@ -340,31 +340,31 @@ void M_I(int row, int col) M_I(601, row, col); } -// Use cards. You may provide a single position, multiple rows with the same column, or multiple cards at the same position. -// *** Usage: -// C(359, CHERRY, 2, 9)------------------- Place cherry at 2-9, taking effect at 359cs -// C(400, {PUFF, SUN}, {1, 2}, 9)--------- Place puff-shroom at 1-9 and sun-shroom at 2-9 -// C(359, {LILY, DOOM, COFFEE}, 3, 9)----- Place lily pad, doom, and coffee bean at 3-9 +// 用卡. 可提供单一坐标, 多行同列, 或多卡同坐标. +// *** 使用示例: +// C(359, CHERRY, 2, 9)-------------------于2-9放置樱桃, 359cs生效 +// C(400, {PUFF, SUN}, {1, 2}, 9)---------于1-9放置小喷, 2-9放置阳光菇 +// C(359, {LILY, DOOM, COFFEE}, 3, 9)-----于3-9放置荷叶, 核武, 咖啡豆 // -// *** Alternative forms of card time: -// C(after(110), ...)----------- Same usage, taking effect after 110cs -// C(exact(800), ...)----------- Use card-based time instead of cob-based time, taking effect at 800cs -// C(after(exact(..)), ...)----- Combination of the above two +// *** 生效时间的变种: +// C(after(110), ...)-----------用法同上, 延迟110cs生效 +// C(exact(800), ...)-----------不使用炮等效时间, 800cs生效 +// C(after(exact(..)), ...)-----以上两者的结合 // -// *** Specify shovel time: -// C(400, keep(266), ...)------- Shovel 266cs after effect time -// C(400, until(1036), ...)----- Shovel at 1036cs -// Note: containers (lily pad, flower pot) will be shoveled as well. +// *** 指定铲除时机: +// C(400, keep(266), ...)-------放置后266cs铲 +// C(400, until(1036), ...)-----1036cs铲 +// 注意: 容器会被一并铲除. void C(Time time, ShovelTime shovel_time, const std::vector& plant_types, const std::vector& rows, int col) { if (plant_types.empty()) { - _SimpleAvZInternal::error("C", "Must provide the card to use"); + _SimpleAvZInternal::error("C", "要用的卡片不可为空"); } if (rows.empty()) { - _SimpleAvZInternal::error("C", "Must provide which row to use the card"); + _SimpleAvZInternal::error("C", "用卡行数不可为空"); } if (plant_types.size() != rows.size()) { - _SimpleAvZInternal::error("C", "Number of cards and number of rows must be the same\nNumber of cards: #\nNumber of rows: #", plant_types.size(), rows.size()); + _SimpleAvZInternal::error("C", "卡片数与行数不一致\n卡片数: #\n行数: #", plant_types.size(), rows.size()); } for (size_t i = 0; i < plant_types.size(); i++) { auto plant_type = plant_types.at(i); @@ -402,7 +402,7 @@ void C(Time time, const std::vector& plant_types, const std::vector& plant_types, int row, int col) { if (plant_types.empty()) { - _SimpleAvZInternal::error("C", "Must provide the card to use"); + _SimpleAvZInternal::error("C", "要用的卡片不可为空"); } for (const auto& plant_type : plant_types) { _SimpleAvZInternal::validate_card_position(plant_type, row, col, "C"); @@ -447,11 +447,11 @@ void C(Time time, PlantType plant_type, int row, int col) C(time, ShovelTime(), {{plant_type}}, {{row}}, col); } -// Decide whether or not to use cards depending on zombies. -// You may either check if a certain type of zombie exists, or check if certain types of zombie's x is smaller than some threshold. -// *** Usage: -// C_IF(exist(ZOMBONI), 400, SPIKEWEED, 1, 9)------- If there is zomboni in row 1, place spikeweed at 1-9 at 400cs -// C_IF(pos({GARG, GIGA}, 680), 400, POT, 1, 8)----- If there is garg or giga with int(x)≤680, place flower pot at 1-8 at 400cs +// 智能用卡. 根据本行僵尸情况决定是否用卡. +// 提供"僵尸是否存在", 以及"僵尸x是否小于某值"两种判断方式. +// *** 使用示例: +// C_IF(exist(ZOMBONI), 400, SPIKEWEED, 1, 9)-------若本行存在冰车, 于400cs在1-9放置地刺 +// C_IF(pos({GARG, GIGA}, 680), 400, POT, 1, 8)-----若本行存在int(x)≤680的白眼或红眼, 于400cs在1-8放置花盆 void C_IF(const std::function& condition, Time time, ShovelTime shovel_time, const PlantType& plant_type, int row, int col) { _SimpleAvZInternal::validate_card_position(plant_type, row, col, "C"); diff --git a/crescendo/SimpleAvZ/SimpleAvZ/error.h b/crescendo/SimpleAvZ/SimpleAvZ/error.h index 0db196e..564b51d 100644 --- a/crescendo/SimpleAvZ/SimpleAvZ/error.h +++ b/crescendo/SimpleAvZ/SimpleAvZ/error.h @@ -8,7 +8,7 @@ template void error(const std::string& func_name, const std::string& content, Args... args) { AvZ::SetErrorMode(AvZ::POP_WINDOW); - AvZ::ShowErrorNotInQueue("[Error when calling " + func_name + " ]\n" + content, args...); + AvZ::ShowErrorNotInQueue("[调用 " + func_name + " 时出错]\n" + content, args...); throw ""; } diff --git a/crescendo/SimpleAvZ/SimpleAvZ/global.h b/crescendo/SimpleAvZ/SimpleAvZ/global.h index b5c5b8c..772315c 100644 --- a/crescendo/SimpleAvZ/SimpleAvZ/global.h +++ b/crescendo/SimpleAvZ/SimpleAvZ/global.h @@ -43,7 +43,7 @@ class Global : AvZ::GlobalVar { Global global; -// scene related +// scene 相关 bool is_night_time() { auto scene = AvZ::GetMainObject()->scene(); diff --git a/crescendo/SimpleAvZ/SimpleAvZ/ice_filler.h b/crescendo/SimpleAvZ/SimpleAvZ/ice_filler.h index 6216488..33c0556 100644 --- a/crescendo/SimpleAvZ/SimpleAvZ/ice_filler.h +++ b/crescendo/SimpleAvZ/SimpleAvZ/ice_filler.h @@ -15,10 +15,10 @@ void set_ice_internal(const std::vector& ice_positions) auto row = pos.row; auto col = pos.col; if (row < 1 || row > max_row) { - _SimpleAvZInternal::error("SetIce", "Ice row should be within 1~#: #", max_row, row); + _SimpleAvZInternal::error("SetIce", "存冰行数应在1~#内\n存冰行数: #", max_row, row); } if (col < 1 || col > 9) { - _SimpleAvZInternal::error("SetIce", "Ice col should be within 1~9: #", col); + _SimpleAvZInternal::error("SetIce", "存冰列数应在1~9内\n存冰列数: #", col); } } @@ -32,11 +32,11 @@ void set_ice_internal(const std::vector& ice_positions) } // namespace _SimpleAvZInternal -// Set where to store ices in daytime. -// If effect time is not specified, it defaults to game start (wave 1, -599cs). -// *** Usage: -// SetIce({{1, 1}, {1, 2}})----- Store and use ices at 1-1, 1-2 (use 1-2 first), effective since game start [EXT] -// SetIce(400, {...})----------- Effective since 400cs +// 设置存冰位置. +// 若不指定生效时间, 默认在 wave 1, -599cs 生效. +// *** 使用示例: +// SetIce({{1, 1}, {1, 2}})-----在1-1, 1-2存冰(优先使用1-2)[外] +// SetIce(400, {...})-----------400cs生效 void SetIce(Time time, const std::vector& ice_positions) { _SimpleAvZInternal::get_effect_time_and_set_time(time, "SetIce"); @@ -49,16 +49,16 @@ void SetIce(const std::vector& ice_positions) _SimpleAvZInternal::set_ice_internal(ice_positions); } -// Use ice in daytime. Effect time is auto-corrected. -// If effect time is not specified, it defaults to 601cs of the current wave (perfect ice for next wave). -// *** Usage: -// I()--------------- Use ice, taking effect at 601cs (perfect ice) -// I(after(210))----- Use ice, takeing effect after 210cs (ice3), recommended to be used after activation cobs -// I(359)------------ Use ice, taking effect at 359cs +// 白昼点冰. 自带生效时机修正. +// 若不指定生效时间, 默认在本波 601cs 生效. +// *** 使用示例: +// I()---------------点冰, 601cs生效(完美预判冰) +// I(after(210))-----延迟210cs生效(ice3), 推荐在激活炮后使用 +// I(359)------------359cs生效 void I(Time time = Time(601)) { if (_SimpleAvZInternal::is_night_time()) { - _SimpleAvZInternal::error("I", "Cannot use daytime version of I() at nighttime\nPlease provide ice position"); + _SimpleAvZInternal::error("I", "不可在夜间使用白昼版本的I()\n请提供用冰位置"); } auto effect_time = _SimpleAvZInternal::get_card_effect_time(time, {ICE_SHROOM, COFFEE_BEAN}, "I"); diff --git a/crescendo/SimpleAvZ/SimpleAvZ/iterator.h b/crescendo/SimpleAvZ/SimpleAvZ/iterator.h index 59b2401..be022d1 100644 --- a/crescendo/SimpleAvZ/SimpleAvZ/iterator.h +++ b/crescendo/SimpleAvZ/SimpleAvZ/iterator.h @@ -31,7 +31,7 @@ class WavesValidator : AvZ::GlobalVar { } } if (!duplicate_waves.empty()) { - error("waves", "duplicate wave in waves(): " + concat(duplicate_waves, ",")); + error("waves", "waves调用的波次不可重复.\n重复的波次: " + concat(duplicate_waves, ",")); } } }; @@ -45,7 +45,7 @@ class Wave { : value(v) { } - + operator int() const { return value; @@ -108,12 +108,12 @@ class Waves { std::vector wave_range_to_waves_vec(const std::array& wave_range, int step, const std::string& func_name) { if (wave_range[0] > wave_range[1]) { - _SimpleAvZInternal::error(func_name, "Start wave should ≤ end wave\nStart wave: #\nEnd wave: #", wave_range[0], wave_range[1]); + _SimpleAvZInternal::error(func_name, "起始波数应≤终止波数\n起始波数: #\n终止波数: #", wave_range[0], wave_range[1]); } std::vector<_SimpleAvZInternal::Wave> waves_vec; for (int w = wave_range[0]; w <= wave_range[1]; w += step) { if (w < 1 || w > 20) { - _SimpleAvZInternal::error(func_name, "Wave should be within 1~20: #", w); + _SimpleAvZInternal::error(func_name, "波数应在1~20内\n当前为: #", w); } _SimpleAvZInternal::waves_validator.waves.push_back(w); waves_vec.push_back( @@ -124,21 +124,21 @@ std::vector wave_range_to_waves_vec(const std::array& wave_range, } -// Set wave. -// Basic usage: for (auto w : waves(...)) { -// // here goes your operations... -// } -// *** Usage: -// waves(1, 2, 3)----------------- w1, w2, w3 (may specify any number of waves) -// waves({1, 9}, 4)--------------- from w1 to w9, every 4 waves -// waves({1, 9}, {11, 19}, 4)----- from w1 to w9 and from w11 to w19, every 4 waves +// 设定波次. +// 基础用法: for (auto w : waves(...)) { +// // 具体操作 +// } +// *** 使用例: +// waves(1, 2, 3)-----------------w1, w2, w3(可指定任意多个) +// waves({1, 9}, 4)---------------w1-w9 每4波一循环 +// waves({1, 9}, {11, 19}, 4)-----w1-w9, w11-w19 每4波一循环 template _SimpleAvZInternal::Waves waves(Args... args) { std::vector<_SimpleAvZInternal::Wave> waves_vec = {_SimpleAvZInternal::Wave(args)...}; for (const auto& w : waves_vec) { if (w.value < 1 || w.value > 20) { - _SimpleAvZInternal::error("waves", "Wave should be within 1~20: #", w.value); + _SimpleAvZInternal::error("waves", "波数应在1~20内\n波数: #", w.value); } _SimpleAvZInternal::waves_validator.waves.push_back(w.value); } @@ -148,7 +148,7 @@ _SimpleAvZInternal::Waves waves(Args... args) _SimpleAvZInternal::Waves waves(const std::array& wave_range_1, const std::array& wave_range_2, int step) { if (step <= 0) { - _SimpleAvZInternal::error("waves", "Step should >0: #", step); + _SimpleAvZInternal::error("waves", "循环长度应>0\n循环长度: #", step); } auto waves_vec_1 = _SimpleAvZInternal::wave_range_to_waves_vec(wave_range_1, step, "waves"); @@ -160,7 +160,7 @@ _SimpleAvZInternal::Waves waves(const std::array& wave_range_1, const st _SimpleAvZInternal::Waves waves(const std::array& wave_range, int step) { if (step <= 0) { - _SimpleAvZInternal::error("waves", "Step should >0: #", step); + _SimpleAvZInternal::error("waves", "循环长度应>0\n循环长度: #", step); } return _SimpleAvZInternal::Waves(_SimpleAvZInternal::wave_range_to_waves_vec(wave_range, step, "waves")); diff --git a/crescendo/SimpleAvZ/SimpleAvZ/time.h b/crescendo/SimpleAvZ/SimpleAvZ/time.h index c827e3c..f25b5a3 100644 --- a/crescendo/SimpleAvZ/SimpleAvZ/time.h +++ b/crescendo/SimpleAvZ/SimpleAvZ/time.h @@ -80,7 +80,7 @@ namespace _SimpleAvZInternal { int get_delayed_time_and_update(int delay_time, const std::string& func_name) { if (!global.is_last_effect_time_initialized()) { - error(func_name + "-->after", "There is no time base for delay. Please use functions with fixed time first."); + error(func_name + "-->after", "没有延迟的基准, 请先使用固定时间的用炮/用卡函数"); } global.last_effect_time += delay_time; @@ -92,7 +92,7 @@ int get_delayed_time_and_update(int delay_time, const std::string& func_name) int get_effect_time(Time time, const std::string& func_name) { if (!global.is_last_effect_wave_initialized()) { - error(func_name, "You haven't set wave yet. Please use this function as such:\nfor (auto w : waves(...)){\n // this function\n}"); + error(func_name, "没有设置波数, 请用以下方式调用本函数:\nfor (auto w : waves(...)){\n // 调用本函数\n}"); } switch (time.type) { @@ -110,7 +110,7 @@ int get_effect_time(Time time, const std::string& func_name) void set_time_inside(int time, const std::string& func_name) { if (!global.is_last_effect_wave_initialized()) { - error(func_name, "You haven't set wave yet. Please use this function as such:\nfor (auto w : waves(...)){\n // this function\n}"); + error(func_name, "没有设置波数, 请用以下方式调用本函数:\nfor (auto w : waves(...)){\n // 调用本函数\n}"); } AvZ::SetTime(time, global.last_effect_wave); } @@ -124,7 +124,7 @@ void get_effect_time_and_set_time(Time time, const std::string& func_name) void set_time_outside(int time, int wave, const std::string& func_name) { if (global.is_last_effect_wave_initialized()) { - error(func_name, "If time is omitted, you must use this function outside waves() loops."); + error(func_name, "若省略生效时间, 需在waves()循环节外使用"); } AvZ::SetTime(time, wave); diff --git a/crescendo/SimpleAvZ/SimpleAvZ/zombie.h b/crescendo/SimpleAvZ/SimpleAvZ/zombie.h index ef84bcc..7789261 100644 --- a/crescendo/SimpleAvZ/SimpleAvZ/zombie.h +++ b/crescendo/SimpleAvZ/SimpleAvZ/zombie.h @@ -59,44 +59,44 @@ struct EnsureExistInfo { void validate() const { if (INVALID_ZOMBIES.count(zombie_type)) { - error("EnsureExist", "Unsupported zombie type: #", zombie_type); + error("EnsureExist", "不支持的僵尸类型: #", zombie_type); } for (const auto& row : rows) { if (row < 1 || row > get_max_spawn_row()) { - error("EnsureExist", "Zombie row should be within 1~#: #", get_max_spawn_row(), row); + error("EnsureExist", "僵尸行数应在1~#内\n无效的行数: #", get_max_spawn_row(), row); } } - auto detail_str = "Zombie type: " + std::to_string(static_cast(zombie_type)) + "\nZombie rows: " + concat(rows, ","); + auto detail_str = "僵尸类型: " + std::to_string(static_cast(zombie_type)) + "\n僵尸所在行: " + concat(rows, ","); if (has_water_rows()) { if (AQUATIC_ZOMBIES.count(zombie_type)) { if (AvZ::GetMainObject()->scene() == 8) { - error("EnsureExist", "Cannot spawn snorkel or dolphin in aquarium scene\n" + detail_str); + error("EnsureExist", "水族馆不出潜水与海豚\n" + detail_str); } else if (rows.count(3) + rows.count(4) != rows.size()) { - error("EnsureExist", "Cannot spawn snorkel or dolphin in non-water rows\n" + detail_str); + error("EnsureExist", "非水路不出潜水与海豚\n" + detail_str); } } else if (zombie_type != BALLOON_ZOMBIE) { - if ((rows.count(3) || rows.count(4))) { - error("EnsureExist", "Setting zombies except snorkel, dolphin, or balloon in water rows is not supported yet\n" + detail_str); + if (rows.count(3) || rows.count(4)) { + error("EnsureExist", "暂不支持在水路设定潜水、海豚、气球以外的僵尸\n" + detail_str); } } } else { if (AQUATIC_ZOMBIES.count(zombie_type)) { - error("EnsureExist", "Cannot spawn snorkel or dolphin in non-backyard scenes\n" + detail_str); + error("EnsureExist", "非后院不出潜水与海豚\n" + detail_str); } if (no_dancing_in_side_rows() && zombie_type == DANCING_ZOMBIE && (rows.count(1) || rows.count(get_max_spawn_row()))) { - error("EnsureExist", "Cannot spawn dancer in side rows\n" + detail_str); + error("EnsureExist", "边路不出舞王\n" + detail_str); } if (no_zomboni() && zombie_type == ZOMBONI) { - error("EnsureExist", "Cannot spawn zomboni in night scene\n" + detail_str); + error("EnsureExist", "黑夜不出冰车\n" + detail_str); } if (is_roof() && (zombie_type == DANCING_ZOMBIE || zombie_type == DIGGER_ZOMBIE)) { - error("EnsureExist", "Cannot spawn dancer or digger in roof scenes\n" + detail_str); + error("EnsureExist", "屋顶不出舞王与矿工\n" + detail_str); } } } @@ -120,7 +120,7 @@ struct EnsureAbsentInfo { valid_rows_set.erase(banned_row); } if (valid_rows_set.empty()) { - error("EnsureAbsent", "Cannot ban all valid rows", zombie_type); + error("EnsureAbsent", "不可禁用所有合法行", zombie_type); } valid_rows = std::vector(valid_rows_set.begin(), valid_rows_set.end()); } @@ -128,45 +128,45 @@ struct EnsureAbsentInfo { void validate() const { if (INVALID_ZOMBIES.count(zombie_type)) { - error("EnsureAbsent", "Unsupported zombie type: #", zombie_type); + error("EnsureAbsent", "不支持的僵尸类型: #", zombie_type); } for (const auto& banned_row : banned_rows) { if (banned_row < 1 || banned_row > get_max_spawn_row()) { - error("EnsureAbsent", "Banned row should be within 1~#: #", get_max_spawn_row(), banned_row); + error("EnsureAbsent", "禁用行数应在1~#内\n无效的行数: #", get_max_spawn_row(), banned_row); } } - auto detail_str = "Zombie type: " + std::to_string(static_cast(zombie_type)) + "\nBanned rows: " + auto detail_str = "僵尸类型: " + std::to_string(static_cast(zombie_type)) + "\n禁用行: " + concat(banned_rows, ","); if (has_water_rows()) { if (AQUATIC_ZOMBIES.count(zombie_type)) { if (AvZ::GetMainObject()->scene() == 8) { - error("EnsureAbsent", "Cannot spawn snorkel or dolphin in aquarium scene\n" + detail_str); + error("EnsureAbsent", "水族馆不出潜水与海豚\n" + detail_str); } else if (banned_rows.count(3) + banned_rows.count(4) != banned_rows.size()) { - error("EnsureAbsent", "Cannot spawn snorkel or dolphin in non-water rows\n" + detail_str); + error("EnsureAbsent", "非水路不出潜水与海豚\n" + detail_str); } } else if (zombie_type != BALLOON_ZOMBIE) { if (banned_rows.count(3) || banned_rows.count(4)) { - error("EnsureAbsent", "Banning zombies except snorkel, dolphin, or balloon in water rows is not supported yet\n" + detail_str); + error("EnsureAbsent", "暂不支持在水路禁用潜水、海豚、气球以外的僵尸\n" + detail_str); } } } else { if (AQUATIC_ZOMBIES.count(zombie_type)) { - error("EnsureAbsent", "Cannot spawn snorkel or dolphin in non-backyard scenes\n" + detail_str); + error("EnsureAbsent", "非后院不出潜水与海豚\n" + detail_str); } if (no_dancing_in_side_rows() && zombie_type == DANCING_ZOMBIE && (banned_rows.count(1) || banned_rows.count(get_max_spawn_row()))) { - error("EnsureAbsent", "Cannot spawn dancer in side rows\n" + detail_str); + error("EnsureAbsent", "边路不出舞王\n" + detail_str); } if (no_zomboni() && zombie_type == ZOMBONI) { - error("EnsureAbsent", "Cannot spawn zomboni in night scene\n" + detail_str); + error("EnsureAbsent", "黑夜不出冰车\n" + detail_str); } if (is_roof() && (zombie_type == DANCING_ZOMBIE || zombie_type == DIGGER_ZOMBIE)) { - error("EnsureAbsent", "Cannot spawn dancer or digger in roof scenes\n" + detail_str); + error("EnsureAbsent", "屋顶不出舞王与矿工\n" + detail_str); } } } @@ -209,12 +209,11 @@ std::array, 6 + 1>, GIGA_GARGANTUAR + 1> get_zombie_ } // namespace _SimpleAvZInternal -// Ensure some zombies appear in certain rows for the current wave. -// Must be used within waves() loops. -// *** Usage: -// EnsureExist(GIGA)----------------------------- Ensure giga appears in all reasonable rows -// EnsureExist({GIGA, 2, 3})--------------------- Ensure giga appears in row 2 & 3 -// EnsureExist({{GIGA, 2, 3}, {ZOMBONI, 4}})----- Ensure giga appears in row 2 & 3 and zomboni appears in row 4 +// 确保本波某类僵尸出现在某行. 需在waves()循环节内使用. 对本波有效. +// *** 使用示例: +// EnsureExist(GIGA)-----------------------------确保红眼出现在所有合理行 +// EnsureExist({GIGA, 2, 3})---------------------确保红眼出现在第2,3行 +// EnsureExist({{GIGA, 2, 3}, {ZOMBONI, 4}})-----确保红眼出现在第2,3行, 冰车出现在第4行 void EnsureExist(const std::vector<_SimpleAvZInternal::EnsureExistInfo>& ensure_exist_info_list) { std::set seen_zombie_types; @@ -222,7 +221,7 @@ void EnsureExist(const std::vector<_SimpleAvZInternal::EnsureExistInfo>& ensure_ info.validate(); if (seen_zombie_types.count(info.zombie_type)) { - _SimpleAvZInternal::error("EnsureExist", "Duplicate zombie type: #", info.zombie_type); + _SimpleAvZInternal::error("EnsureExist", "僵尸类型重复: #", info.zombie_type); } seen_zombie_types.insert(info.zombie_type); } @@ -254,7 +253,7 @@ void EnsureExist(const std::vector<_SimpleAvZInternal::EnsureExistInfo>& ensure_ best_src_row = row; } if (zombie_index[zombie_type][best_src_row].size() <= 1) { - AvZ::ShowErrorNotInQueue("Not enough zombies of type # to ensure it appears in row #", zombie_type, target_row); + AvZ::ShowErrorNotInQueue("僵尸数量不足, 无法确保种类为 # 的僵尸出现在 # 行", zombie_type, target_row); continue; } } @@ -275,11 +274,10 @@ void EnsureExist(const _SimpleAvZInternal::EnsureExistInfo& ensure_exist_info) EnsureExist(std::vector<_SimpleAvZInternal::EnsureExistInfo> {ensure_exist_info}); } -// Ensure some zombies are absent in certain rows for the current wave. -// Must be used within waves() loops. -// *** Usage: -// EnsureAbsent({GIGA, 2, 3})--------------------- Ensure giga are absent in row 2 & 3 -// EnsureAbsent({{GIGA, 2, 3}, {ZOMBONI, 4}})----- Ensure giga are absent in row 2 & 3 and zomboni are absent in row 4 +// 禁止本波某类僵尸出现在某行. 需在waves()循环节内使用. 对本波有效. +// *** 使用示例: +// EnsureAbsent({GIGA, 2, 3})---------------------禁止红眼出现在第2,3行 +// EnsureAbsent({{GIGA, 2, 3}, {ZOMBONI, 4}})-----禁止红眼出现在第2,3行, 禁止冰车出现在第4行 void EnsureAbsent(const std::vector<_SimpleAvZInternal::EnsureAbsentInfo>& ensure_absent_info_list) { std::set seen_zombie_types; @@ -287,7 +285,7 @@ void EnsureAbsent(const std::vector<_SimpleAvZInternal::EnsureAbsentInfo>& ensur info.validate(); if (seen_zombie_types.count(info.zombie_type)) { - _SimpleAvZInternal::error("EnsureAbsent", "Duplicate zombie type: #", info.zombie_type); + _SimpleAvZInternal::error("EnsureAbsent", "僵尸类型重复: #", info.zombie_type); } seen_zombie_types.insert(info.zombie_type); } diff --git a/crescendo/SimpleAvZ/doc/README(eng).md b/crescendo/SimpleAvZ/doc/README(eng).md index 41701c4..5ef23aa 100644 --- a/crescendo/SimpleAvZ/doc/README(eng).md +++ b/crescendo/SimpleAvZ/doc/README(eng).md @@ -154,6 +154,7 @@ Specify the shovel time after using cards. RM(400, SUNFLOWER); // Shovel all sunflowers at 400cs RM(400, PUMPKIN, 1, 1); // Shovel pumpkin at 1-1 (if there is no pumpkin, do nothing) RM(400, 1, 1); // Shovel 1-1 (non-pumpkin plants first) +RM(400, {{1, 1}, {1, 2}}); // Shovel 1-1, 1-2 (non-pumpkin plants first) RM(400, {1, 2, 5, 6}, 9); // Shovel 1-9, 2-9, 5-9, 6-9 (non-pumpkin plants first) RM(after(751), ...); // Same usage, taking effect after 751cs ```