SDL中文论坛

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 5257|回复: 4
打印 上一主题 下一主题

[MOD] 基于条件的动作(Conditional Actions)

[复制链接]

149

主题

331

帖子

2445

积分

版主

Rank: 7Rank: 7Rank: 7

积分
2445
跳转到指定楼层
楼主
发表于 2020-11-29 11:42:21 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
如果满足特定条件,这些动作就会被执行。这里不叙述动作,主要说条件。条件是由一些WML块来描述的,它可用于[side]和[event]块。

[if]
如果满足这个块包含的条件,执行相应动作。它底下会有:
  • 条件块:描述条件。如果条件满足则执行[then]块内动作,否则执行[else]内作动作。
  • [then]块:描述动作。如果条件满足就执行它描述的动作。
  • [else]块:描述动作。如果条件不满足就执行它描述的动作。

以下是一个使用[if]例子:
  1. Example-1

  2. [if]
  3.         [variable]
  4.                 name=player
  5.                 equals=zhouyu
  6.         [/variable]
  7.         [then]
  8.                 controller=ai
  9.         [/then]
  10.         [else]
  11.                 controller=human
  12.         [/else]
  13. [/if]
复制代码
[variable]是条件块,它的条件判断是player是否等于zhouyu。如果player等于zhouyu,执行[then]块中动作:controller=ai,否则执行controller=human。

[switch]
待看.....http://wiki.wesnoth.org/ConditionalActionsWML#Condition_Tags

[while]
待看.....http://wiki.wesnoth.org/ConditionalActionsWML#Condition_Tags


条件块
条件块用于描述要执行特定动作必须满足的条件,像Example-1的[variable]。程序没法无限制表示条件,支持以下这三种格式的条件块。

[have_unit]
如果存在一个或count个HP不为零且满足StandardUnitFilter指定条件的单位,这块判断结果为TRUE。
  • StandardUnitFilter:标准单位筛选设定。
  • count(可选):如果指定,则要count个满足StandardUnitFilter的单位这条件才返回TRUE。在值上,它可能是一个数字、范围、或逗号隔开的范围。如果不指定,则使用1-99999,也就是说只要有一个满足StandardUnitFilter的单位这条件就返回TRUE。

注:count书写格式
1、要等于某个数字。count=<数字>。count=2表示要存在2个单位。
2、某段范围内的任一个数字。count=<上限>-<下限>。count=2-59表示只要存在“>=2并且<=59”个单位。
3、数段范围内的任一个数字。count=<上限1>-<下限1>,<上限2>-<下限2>,...。count=1,10-15,245-589,998表示只要存在1个或“>=10并且<=15”个或“>=245并且<=589”个或998个单位。

[have_location]
如果存在满足StandardUnitFilter指定条件的格子,这块判断结果为TRUE。
  • StandardLocationFilter:格子选择设定。
  • count(可选):意义类似[have_unit]中的count。


[variable]
测试一个WML变量和一个给定值,把这个结果作为这个块的判断结果。
  • name:要被测试的WML变量,例如以Example-1中的player。
  • <比较>:比较可以使用下面列出的关键字,说明时$name表示WML变量,Example-1中就是player;value指此刻传下来的值,Example-1中是zhouyu。
    • contains:$name内容包含value。
    • equals:$name字符串等于value。
    • not_equals:$name字符串不等于value。
    • numerical_equals:把$name和value都转换为double值,这两个值要相等。
    • numerical_not_equals:把$name和value都转换为double值,这两个值要不相等。
    • 注:相比equals,numerial_equals和boolean_equals效率要低。举个例子,“1”和“1.0”,用equals时它们是不相等,但以numerial_equals它们是相等的;“yes”和“on”,用equals时它们是不相等,但以boolean_equals它们是相等的。(这同时解释了为什么equals执行更快。用equals在直观上就可以看出是否相等,而不用理解这个值是怎么个写法,像这个WML变量是boolean型)
    • greater_than:把$name和value都转换为double值,$name>value。
    • greater_than_equal_to:把$name和value都转换为double值,$name>=value。
    • less_than:把$name和value都转换为double值,$name<value。
    • less_than_equal_to:把$name和value都转换为double值,$name<=value。
    • boolean_equals:把$name和value都转换为bool值,$name等于value。
    • boolean_not_equal:把$name和value都转换为bool值,$name不等于value。



布尔变量值
当一个WML变量要被解释为boolean类型时,这看作是false还是ture时的值。
看作fase的字符串值:no,fase,off,0,0.0,(uninitialized);
看作true的字符串值:yes,true,on,1,0.1,(任何一人非零数字);

准条件标签
这些标签不是“真正”的条件。它们包在条件块外头,把这些条件块组合成一个新的条件。这个新的条件要返回ture,可能是它子条件都是true(and时),可能是子条件只要有一个true(or时),可能是子条件是false(not时)。在书写这个准条件标签到时要注意顺序,它们是以着这个条件顺序被处理的。另外要注意,第一个条件块外头不应该有or标签,
[and]
与。条件要判断结果是true,除了其它子块是true,这块也须是true。
[or]
或。条件要判断结果是true,只要这子块是true。
[not]
非。条件要判断结果是true,这子块是false。
回复

使用道具 举报

149

主题

331

帖子

2445

积分

版主

Rank: 7Rank: 7Rank: 7

积分
2445
沙发
 楼主| 发表于 2020-11-29 11:42:56 | 只看该作者

[side]中的条件块

[side]用于描述阵营,针对玩家选择角色不同阵营描述往往不用,像玩家选周瑜时,周瑜阵营的控制属性human,玩家选排周瑜时,这阵营控制属性就是ai。为一个[side]就要实现这种区别描述,此时就须要用条件块。
  1. [side]
  2.         side=3
  3.         [if]
  4.                 [variable]
  5.                         name=player
  6.                         equals=zhouyu
  7.                 [/variable]
  8.                 [then]
  9.                         controller=human
  10.                         gold=150
  11.                         income=0
  12.                 [/then]
  13.                 [else]
  14.                         [if]
  15.                                 [variable]
  16.                                         name=player
  17.                                         equals=zhouyu
  18.                                 [/variable]
  19.                                 [then]
  20.                                         controller=ai
  21.                                         gold=200
  22.                                         income=80
  23.                                 [/then]
  24.                                 [else]
  25.                                         controller=ai
  26.                                         gold=300
  27.                                         income=80
  28.                                 [/else]
  29.                         [/if]
  30.                 [/else]
  31.         [/if]
  32.         ......
  33. [/side]
复制代码
玩家选周瑜时,控制属性是human,初始金150,每回合入库金0。玩家选刘备时,控制属性是ai,初始金200,每回合入库金80。玩家选的既不是周瑜又不是刘备时,控制属性是ai,初始金300,每回合入库金80。

对于side中的条件块几点说明:
一、条件块标签能是能是[if]。
二、一个side可以有多个[if]块。
回复 支持 反对

使用道具 举报

149

主题

331

帖子

2445

积分

版主

Rank: 7Rank: 7Rank: 7

积分
2445
板凳
 楼主| 发表于 2020-11-29 11:43:26 | 只看该作者

[event]中的条件块

[event]用于事件,有时须在事件中跟据当前状态来对事件条件执行不同处理,例如常见的选择角色。
以下是战役胜利事件
  1. [event]
  2.         name=last breath
  3.         first_time_only=no
  4.         [filter]
  5.                 last_city=yes
  6.         [/filter]
  7.         [if]
  8.                 [variable]
  9.                         name=player
  10.                         equals=zhouyu
  11.                 [/variable]
  12.                 [and]
  13.                         [variable]
  14.                                 name=unit.side
  15.                                 equals=2
  16.                         [/variable]
  17.                 [/and]
  18.                 [then]
  19.                         [message]
  20.                                 speaker=6
  21.                                 message= _ "stop word: 1"
  22.                         [/message]
  23.                         [message]
  24.                                 speaker=39
  25.                                 message= _ "stop word: 2"
  26.                         [/message]
  27.                         [kill]
  28.                                 master_hero=39
  29.                                 animate=yes
  30.                         [/kill]
  31.                         [endlevel]
  32.                                 result=victory
  33.                         [/endlevel]
  34.                 [/then]
  35.                 [else]
  36.                         [if]
  37.                                 [variable]
  38.                                         name=player
  39.                                         equals=liubei
  40.                                 [/variable]
  41.                                 [and]
  42.                                         [variable]
  43.                                                 name=unit.side
  44.                                                 equals=2
  45.                                         [/variable]
  46.                                 [/and]
  47.                                 [then]
  48.                                         [message]
  49.                                                 speaker=4
  50.                                                 message= _ "stop word: 1"
  51.                                         [/message]
  52.                                         [message]
  53.                                                 speaker=39
  54.                                                 message= _ "stop word: 2"
  55.                                         [/message]
  56.                                         [kill]
  57.                                                 master_hero=39
  58.                                                 animate=yes
  59.                                         [/kill]
  60.                                         [endlevel]
  61.                                                 result=victory
  62.                                         [/endlevel]
  63.                                 [/then]       
  64.                                 [else]
  65.                                         [if]
  66.                                                 [variable]
  67.                                                         name=player
  68.                                                         equals=caoren
  69.                                                 [/variable]
  70.                                                 [and]
  71.                                                         [variable]
  72.                                                                 name=unit.side
  73.                                                                 equals=3
  74.                                                         [/variable]
  75.                                                 [/and]       
  76.                                                 [then]       
  77.                                                         [message]
  78.                                                                 speaker=39
  79.                                                                 message= _ "caoren stop word: 1"
  80.                                                         [/message]
  81.                                                         [message]
  82.                                                                 speaker=6
  83.                                                                 message= _ "caoren stop word: 2"
  84.                                                         [/message]
  85.                                                         [kill]
  86.                                                                 master_hero=6
  87.                                                                 animate=yes
  88.                                                         [/kill]
  89.                                                         [endlevel]
  90.                                                                 result=victory
  91.                                                         [/endlevel]
  92.                                                 [/then]
  93.                                         [/if]
  94.                                 [/else]                       
  95.                         [/if]
  96.                 [/else]       
  97.         [/if]       
  98. [/event]
复制代码
当曹仁阵营(阵营2)最后一个城市被攻陷时。满足last_city=yes筛选条件,这事件要被触发。
玩家是周瑜,执行:
  1. [message]
  2.         speaker=6
  3.         message= _ "stop word: 1"
  4. [/message]
  5. [message]
  6.         speaker=39
  7.         message= _ "stop word: 2"
  8. [/message]
  9. [kill]
  10.         master_hero=39
  11.         animate=yes
  12. [/kill]
  13. [endlevel]
  14.         result=victory
  15. [/endlevel]
复制代码
玩家是刘备,执行:
  1. [message]
  2.         speaker=4
  3.         message= _ "stop word: 1"
  4. [/message]
  5. [message]
  6.         speaker=39
  7.         message= _ "stop word: 2"
  8. [/message]
  9. [kill]
  10.         master_hero=39
  11.         animate=yes
  12. [/kill]
  13. [endlevel]
  14.         result=victory
  15. [/endlevel]
复制代码
对于event中的条件块几点说明:
一、条件块中不要包含[filter],条件块中[filter]不会产生筛选作用。
回复 支持 反对

使用道具 举报

149

主题

331

帖子

2445

积分

版主

Rank: 7Rank: 7Rank: 7

积分
2445
地板
 楼主| 发表于 2020-11-29 11:43:51 | 只看该作者

函数:conditional_passed


  1. @cond:[if]块。Example-1中,它child就是[variable]、[then]和[else]块,而值映射是空。
  2. @backwards_compat:false。(可能是个为向后兼容而加的变量)
  3. 返回值:
  4. true:满足条件
  5. false:不满足条件

  6. bool conditional_passed(const unit_map* units, const vconfig cond, bool backwards_compat)
  7. {
  8.         bool allow_backwards_compat = backwards_compat = backwards_compat && utils::string_bool(cond["backwards_compat"], true);
  9.         bool matches = internal_conditional_passed(units, cond, allow_backwards_compat);

  10.         // Handle [and], [or], and [not] with in-order precedence
  11.         int or_count = 0;
  12.         vconfig::all_children_iterator cond_i = cond.ordered_begin();
  13.         vconfig::all_children_iterator cond_end = cond.ordered_end();
  14.         while (cond_i != cond_end) {
  15.                 const std::string& cond_name = cond_i.get_key();
  16.                 const vconfig& cond_filter = cond_i.get_child();

  17.                 // Example-1时这里会被进入三次,#0:cond_name=variable,#1:cond_name=then,#2:cond_name=else

  18.                 if (cond_name == "and") {
  19.                         // Handle [and]
  20.                         // 这里调用的是conditional_passed而不是internal_conditional_passed,也就是说准备条标签下可以再有准条件标签
  21.                         matches = matches && conditional_passed(units, cond_filter, backwards_compat);
  22.                         backwards_compat = false;
  23.                 } else if(cond_name == "or") {
  24.                         // Handle [or]
  25.                         matches = matches || conditional_passed(units, cond_filter, backwards_compat);
  26.                         ++or_count;
  27.                 } else if(cond_name == "not") {
  28.                         // Handle [not]
  29.                         matches = matches && !conditional_passed(units, cond_filter, backwards_compat);
  30.                         backwards_compat = false;
  31.                 }
  32.                 ++cond_i;
  33.         }
  34.         // Check for deprecated [or] syntax
  35.         // 从代码上看,以下是重新解释了[or]块,使用规则:所有[or]须要同时是true,结果才是true。这个规则和通常认为是不一致的,不知wesnoth过去代码是以这规则来的。
  36.         if (matches && or_count > 1 && allow_backwards_compat) {
  37.                 lg::wml_error << "possible deprecated [or] syntax: now forcing re-interpretation\n";
  38.                 /**
  39.                  * @todo For now we will re-interpret it according to the old
  40.                  * rules, but this should be later to prevent re-interpretation
  41.                  * errors.
  42.                  */
  43.                 const vconfig::child_list& orcfgs = cond.get_children("or");
  44.                 for (unsigned int i=0; i < orcfgs.size(); ++i) {
  45.                         if (conditional_passed(units, orcfgs[i])) {
  46.                                 return true;
  47.                         }
  48.                 }
  49.                 return false;
  50.         }
  51.         return matches;
  52. }
复制代码
回复 支持 反对

使用道具 举报

149

主题

331

帖子

2445

积分

版主

Rank: 7Rank: 7Rank: 7

积分
2445
5#
 楼主| 发表于 2020-11-29 11:44:16 | 只看该作者

函数:internal_conditional_passed

  1. static bool internal_conditional_passed(const unit_map* units, const vconfig cond, bool& backwards_compat)
  2. {
  3.         static std::vector<std::pair<int,int> > default_counts = utils::parse_ranges("1-99999");

  4.         // 检查第一种允许的条件块:[have_unit]
  5.         // If the if statement requires we have a certain unit,
  6.         // then check for that.
  7.         const vconfig::child_list& have_unit = cond.get_children("have_unit");
  8.         backwards_compat = backwards_compat && have_unit.empty();
  9.         for (vconfig::child_list::const_iterator u = have_unit.begin(); u != have_unit.end(); ++u) {
  10.                 if (units == NULL)
  11.                         return false;
  12.                 std::vector<std::pair<int,int> > counts = (*u).has_attribute("count")? utils::parse_ranges((*u)["count"]) : default_counts;
  13.                 int match_count = 0;
  14.                 unit_map::const_iterator itor;
  15.                 for (itor = units->begin(); itor != units->end(); ++itor) {
  16.                         if (itor->second.hitpoints() > 0 && game_events::unit_matches_filter(itor, *u)) {
  17.                                 ++match_count;
  18.                                 if (counts == default_counts) {
  19.                                         // by default a single match is enough, so avoid extra work
  20.                                         break;
  21.                                 }
  22.                         }
  23.                 }
  24.                 if (!in_ranges(match_count, counts)) {
  25.                         return false;
  26.                 }
  27.         }

  28.         // 检查第三种允许的条件块:[have_location]
  29.         // If the if statement requires we have a certain location,
  30.         // then check for that.
  31.         const vconfig::child_list& have_location = cond.get_children("have_location");
  32.         backwards_compat = backwards_compat && have_location.empty();
  33.         for (vconfig::child_list::const_iterator v = have_location.begin(); v != have_location.end(); ++v) {
  34.                 std::set<map_location> res;
  35.                 terrain_filter(*v, *units).get_locations(res);

  36.                 std::vector<std::pair<int,int> > counts = (*v).has_attribute("count")? utils::parse_ranges((*v)["count"]) : default_counts;
  37.                 if (!in_ranges<int>(res.size(), counts)) {
  38.                         return false;
  39.                 }
  40.         }

  41.         // 检查第三种允许的条件块:[variable]
  42.         // Check against each variable statement,
  43.         // to see if the variable matches the conditions or not.
  44.         const vconfig::child_list& variables = cond.get_children("variable");
  45.         backwards_compat = backwards_compat && variables.empty();

  46.         foreach (const vconfig &values, variables) {
  47.                 const std::string name = values["name"];
  48.                 const std::string& value = resources::state_of_game->get_variable_const(name);

  49.                 const double num_value = atof(value.c_str());

  50. #define TEST_STR_ATTR(name, test) do { \
  51.                 if (values.has_attribute(name)) { \
  52.                         std::string attr_str = values[name].str(); \
  53.                         if (!(test)) return false; \
  54.                 } \
  55.                 } while (0)

  56. #define TEST_NUM_ATTR(name, test) do { \
  57.                 if (values.has_attribute(name)) { \
  58.                         double attr_num = atof(values[name].c_str()); \
  59.                         if (!(test)) return false; \
  60.                 } \
  61.                 } while (0)

  62.                 TEST_STR_ATTR("equals",                value     == attr_str);
  63.                 TEST_NUM_ATTR("numerical_equals",      num_value == attr_num);
  64.                 TEST_STR_ATTR("not_equals",            value     != attr_str);
  65.                 TEST_NUM_ATTR("numerical_not_equals",  num_value != attr_num);
  66.                 TEST_NUM_ATTR("greater_than",          num_value >  attr_num);
  67.                 TEST_NUM_ATTR("less_than",             num_value <  attr_num);
  68.                 TEST_NUM_ATTR("greater_than_equal_to", num_value >= attr_num);
  69.                 TEST_NUM_ATTR("less_than_equal_to",    num_value <= attr_num);
  70.                 TEST_STR_ATTR("boolean_equals",
  71.                         utils::string_bool(value) == utils::string_bool(attr_str));
  72.                 TEST_STR_ATTR("boolean_not_equals",
  73.                         utils::string_bool(value) != utils::string_bool(attr_str));
  74.                 TEST_STR_ATTR("contains", value.find(attr_str) != std::string::npos);

  75. #undef TEST_STR_ATTR
  76. #undef TEST_NUM_ATTR
  77.         }
  78.         // 3/2/1种条件块都满足,返回true
  79.         return true;
  80. }
复制代码
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|丽谷软件|libsdl.cn

GMT+8, 2025-5-1 22:40 , Processed in 0.065440 second(s), 19 queries .

Powered by Discuz! X3.3

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表