第十一章 地图动作与地图事件(Map Action and Map Event)
我们已经有了剧本,而且可以运行剧本,但我们还缺少对地图的操作控制。
我们这一章来完成地图上的操作,地图的操作将全部由MapAction
控制。
文章目录
六 地图事件的条件(Condition of Map Event)
地图事件是我们地图中所发生的事情,包括:
-
触发条件;
-
触发结果。
它也比较常见,例如:
条件 | 结果 | FE4中实例 |
---|---|---|
地图开始 | 创建各种地图对象 | 战斗开始时的剧情,然后创建地图对象 |
角色到达某个地点 | 获取物品 | 第一章时斧骑士到达海边获取二回攻击斧 |
某回合开始 | 创建各种地图对象 | 某些剧情需要 |
对应角色对话 | 获取物品、提升属性等 | 某些章节对话 |
等等诸如此类的事件。
这一节,我们挑选一些典型的事件来说明。
1 条件类(Class Condition)
每一个事件,大多需要一些条件才能触发,这就需要我们知道这些条件是什么。
且每个事件需要的条件可能是多种,但都需要一个进入的条件(主条件),其它为子条件。
首先,我们先来归类一下条件类型:
创建一个枚举MapEventConditionType
来表示条件类型(它们不是必须的,按需来):
using System;
namespace DR.Book.SRPG_Dev.ScriptManagement
{
[Serializable]
public enum MapEventConditionType
{
NoneCondition = 0,
/// <summary>
/// 回合
/// </summary>
TurnCondition,
/// <summary>
/// 位置
/// </summary>
PositionCondition,
/// <summary>
/// 角色id
/// </summary>
RoleCondition,
/// <summary>
/// 属性
/// </summary>
PropertyCondition,
/// <summary>
/// 角色死亡
/// </summary>
RoleDeadCondition,
/// <summary>
/// 对话
/// </summary>
RoleTalkCondition,
/// <summary>
/// 战斗对话
/// </summary>
RoleCombatTalkCondition,
/// <summary>
/// 物品
/// </summary>
ItemCondition
}
}
这些条件并不都是进入条件,我们规定:
-
NoneCondition
:没有条件,进入地图时触发; -
TurnCondition
:回合条件,当回合开始时触发; -
PositionCondition
:位置条件,当角色到达此坐标时触发,常与RoleCondition
连用; -
RoleCondition
:角色条件,不是主条件,常做为其它条件的子条件使用; -
PropertyCondition
:属性条件,不是主条件,常做为其它条件的子条件使用; -
RoleDeadCondition
:死亡条件,角色死亡时触发; -
RoleTalkCondition
:对话条件,两个角色有对话时触发,常与TurnCondition
连用(在某些回合范围内可对话); -
RoleCombatTalkCondition
:战斗对话条件,两个角色发生战斗时触发; -
ItemCondition
:物品条件,不是主条件,常做为其它条件的子条件使用(例如(不)持有某些物品时)。
这以上只是一些常见条件,都是按需。它们有些只能触发一次,而有些可以触发多次(例如《FE4》中的教会)。
我在这里依然选择了xml
作为保存它们的文件类型。
而这些条件需要返回一个布尔类型,来表示条件是否满足。
创建类:
[Serializable]
public class Condition
{
[XmlIgnore]
public virtual MapEventConditionType type
{
get { return MapEventConditionType.NoneCondition; }
}
public virtual bool GetResult(MapAction action)
{
return true;
}
}
2 回合条件(Turn Condition)
在回合条件中,我们在只有在此回合内才能触发,所以它需要:
-
最小回合;
-
最大回合;
-
回合内的阵营。
只有在阵营对应且在当前回合比最小回合大,比最大回合小时才会触发。
[Serializable]
public class TurnCondition : Condition
{
[XmlAttribute]
public int minTurn;
[XmlAttribute]
public int maxTurn;
[XmlAttribute]
public bool allAttitudeTowards;
[XmlAttribute]
public AttitudeTowards attitudeTowards;
[XmlIgnore]
public override MapEventConditionType type
{
get { return MapEventConditionType.TurnCondition; }
}
public sealed override bool GetResult(MapAction action)
{
if (!allAttitudeTowards && action.turn != attitudeTowards)
{
return false;
}
int turn = action.turnToken;
// 如果最大回合数小于0,则只取最小回合
if (maxTurn < 0)
{
return turn >= minTurn;
}
return turn >= minTurn && turn <= maxTurn;
}
}
3 位置条件(Position Condition)
只有当角色到达这一位置时才会触发。
[Serializable]
public class PositionCondition : Condition
{
[XmlAttribute]
public int x;
[XmlAttribute]
public int y;
[XmlIgnore]
public override MapEventConditionType type
{
get { return MapEventConditionType.PositionCondition; }
}
public override bool GetResult(MapAction action)
{
if (action.selectedUnit == null)
{
return false;
}
Vector3Int position = action.selectedUnit.cellPosition;
return position.x == x && position.y == y;
}
}
4 角色条件与角色死亡条件(Role (Dead) Condition)
只有是这个角色时,才会触发。
[Serializable]
public class RoleCondition : Condition
{
[XmlAttribute]
public int characterId;
[XmlIgnore]
public override MapEventConditionType type
{
get { return MapEventConditionType.RoleCondition; }
}
public override bool GetResult(MapAction action)
{
if (action.selectedUnit == null)
{
return false;
}
Role role = action.selectedUnit.role;
if (role.roleType == RoleType.Following)
{
return false;
}
return role.characterId == characterId;
}
}
而角色死亡条件是只有当角色死亡时触发。
[Serializable]
public class RoleDeadCondition : RoleCondition
{
[XmlIgnore]
public override MapEventConditionType type
{
get { return MapEventConditionType.RoleDeadCondition; }
}
public override bool GetResult(MapAction action)
{
// 必须先存在此角色
RoleModel model = ModelManager.models.Get<RoleModel>();
if (!model.ContainsKey(this.characterId))
{
return false;
}
return model.GetOrCreateRole(this.characterId, RoleType.Unique).isDead;
}
}
5 对话条件与战斗对话条件(Role (Combat) Talk Condition)
对话条件,在角色条件的基础上,增加了目标角色,只有双方都对应才能有对话。
[Serializable]
public class RoleTalkCondition : RoleCondition
{
[XmlAttribute]
public int targetId;
[XmlIgnore]
public override MapEventConditionType type
{
get { return MapEventConditionType.RoleTalkCondition; }
}
public override bool GetResult(MapAction action)
{
if (action.selectedUnit == null
|| action.targetUnit == null
|| action.selectedUnit.role.roleType != RoleType.Unique
|| action.targetUnit.role.roleType != RoleType.Unique)
{
return false;
}
if (action.selectedUnit.role.characterId != characterId
|| action.targetUnit.role.characterId != targetId)
{
return false;
}
return true;
}
}
而战斗对话,只要是双方的角色就会触发。
[Serializable]
public class RoleCombatTalkCondition : RoleTalkCondition
{
[XmlIgnore]
public override MapEventConditionType type
{
get { return MapEventConditionType.RoleCombatTalkCondition; }
}
public override bool GetResult(MapAction action)
{
if (action.selectedUnit == null
|| action.targetUnit == null
|| action.selectedUnit.role.roleType != RoleType.Unique
|| action.targetUnit.role.roleType != RoleType.Unique)
{
return false;
}
if ((action.selectedUnit.role.characterId == characterId
&& action.targetUnit.role.characterId == targetId)
|| (action.selectedUnit.role.characterId == targetId
&& action.targetUnit.role.characterId == characterId))
{
return true;
}
else
{
return false;
}
}
}
6 属性条件(Property Condition)
我们选择的角色中,某些属性在范围内就触发。
[Serializable]
public class PropertyCondition : Condition
{
[XmlAttribute]
public FightPropertyType propertyType;
[XmlAttribute]
public int minValue;
[XmlAttribute]
public int maxValue;
[XmlIgnore]
public override MapEventConditionType type
{
get { return MapEventConditionType.PropertyCondition; }
}
public override bool GetResult(MapAction action)
{
if (action.selectedUnit == null)
{
return false;
}
Role role = action.selectedUnit.role;
FightProperties fightProperties = role.fightProperties;
return fightProperties[propertyType] >= minValue
&& fightProperties[propertyType] <= maxValue;
}
}
7 物品条件(Item Condition)
我们角色持有或者不持有某物品触发。
[Serializable]
public class ItemCondition : Condition
{
[XmlAttribute]
public int characterId = -1;
[XmlAttribute]
public int itemId;
[XmlAttribute]
public bool hold; // 是否持有
[XmlIgnore]
public override MapEventConditionType type
{
get { return MapEventConditionType.ItemCondition; }
}
public override bool GetResult(MapAction action)
{
Role role;
if (characterId < 0)
{
if (action.selectedUnit == null)
{
return false;
}
role = action.selectedUnit.role;
if (role.roleType == RoleType.Following)
{
return false;
}
}
else
{
RoleModel model = ModelManager.models.Get<RoleModel>();
if (!model.ContainsKey(characterId))
{
return false;
}
role = model.GetOrCreateRole(characterId, RoleType.Unique);
}
Item[] items = role.items;
bool hasItem = items.Any(item => item != null && item.itemId == itemId);
return hasItem == hold;
}
}