随机事件与陌生人任务
返回总览。本篇覆盖 SP Ambient/WorldPoint/re_*、RandomChar 和在线 FMRE 启动器。它们都增加开放世界内容密度,但不是同一种任务机制。
1. 三种内容形态#
| 类型 | 组织方式 | 长期状态 |
|---|---|---|
| 单机随机事件 RE | 地图 world point 激活脚本,再判断是否可以展开 | 事件解锁、变体完成位、下次允许时间 |
| 陌生人与怪胎 RC | 有角色、系列任务、入口及剧情条件的支线 | 任务链进展、地图可见性、角色资格 |
| 在线随机事件 FMRE | 会话内主机/客户端协作启动和维护 | 当前事件广播、资源预留、各玩家参与状态 |
“随机”常体现为经过条件筛选后遇到某个预设场景,而非完全程序生成故事。RandomChar 的命名也不能理解成随机生成 NPC 外观。[S1][S2][S4][S5]
2. 单机随机事件的准入漏斗#
CAN_RANDOM_EVENT_LAUNCH 是理解系统的关键。它先确认单机已初始化及事件 ID,再依次检查世界与剧情环境。可见约束包括:[S1,L279 起]
- 玩家高速移动时,在非高内存 PC 分支拒绝启动,以减轻流式加载压力。
- 剧情流是否启用、是否处于重玩、任务引导场景是否阻塞。
- 当前是否已有随机事件,附近是否存在待启动 RC,高优先级电话是否等待。
- 玩家高度是否会暴露事件刷新、角色是否适用、事件是否解锁。
- 事件种类冷却时间、全局随机事件启动间隔、该变体是否完成。
- 普通任务标志、随机事件标志,以及任务类型仲裁是否允许启动。
此图把代码中的判断按职责归类,并不声称每条判断的源文件顺序与图完全一致。关键设计是先阻止不合适的体验,再考虑内容多样性;“刷得多”不是唯一目标。
3. 冷却与完成度有不同时间尺度#
random_event_private.sch 将每类事件的阻塞时长集中配置,接口注释注明单位是游戏小时。例如自行车盗窃为 30,ATM 抢劫为 200,巴士游览为 0;不能把这些数值解读成现实秒。[S2,L98]
eTimeBlockUntil[event] 控制种类级下次可用时间;iREVariationComplete[event] 的 bitset 表示变体完成;全局 g_iLastRandomEventLaunch 与 GET_GAME_TIMER 控制短期遭遇间隔。游戏时刻与游戏运行计时器并存,承担长期重复节奏和短期密度两种任务。
变体数量也不是统一常数:私有表中 ATM 抢劫为 5、押运车为 10、搭便车为 4 等。设计者通过同一机制的地点/角色/对白变体扩大内容量,同时用完成位减少不必要重复。[S2]
4. 深入案例:自行车被盗#
re_bikethief.sc 接收 coords_struct,通过输入位置区分场景变体。启动时若玩家已在室内,或距离生成位置过近而可能看见刷出,则直接退出;通过公共准入后创建 scenario blocking area。[S3,L1235 起]
其状态大致为:加载场景 → 等待盗贼行动 → 追盗贼 → 归还车辆 → 车主离开。加载脚本和玩家正式接入事件不是同一时刻:预加载阶段在外围准备角色,接近后才触发戏剧动作。
内容使用的技巧很具体:
- 先伪装成环境生活。 受害者可以先执行
WORLD_HUMAN_STAND_MOBILE,让场景自然融入街道。 - 关键动作使用序列。 盗贼上车后进入逃跑任务,受害者的看向、跑动、转身、求助动画形成连续表演。
- 用 AI 兜住玩家变数。 预录行驶可以切换到车辆逃跑任务,受惊或遭攻击的角色可进入 flee。
- 反馈随空间变化。 提示镜头、追逐速度、对白和 blip 按事件阶段及距离维护。
- 结局可以延后兑现。 特定完成分支登记角色相关奖励邮件,使短遭遇与后续世界反馈连接。
SHOULD_SCRIPT_CLEANUP 分别处理资源尚未加载、尚未激活、受害者死亡/被玩家攻击/被瞄准、车辆损坏等状态。已经开始追逐后,退出判断不再只由最初 world point 范围决定。这是“预热时容易取消,进入戏剧后保持连续性”的生命周期设计。
5. RC 更接近持续支线#
RandomChar_Controller 有时间段检查、流放区域限制、同地点多个任务的处理、战争迷雾揭示检查、blip 名称颜色更新,以及具体人物提醒。[S4] Process_Random_Character_Mission_State 把每个 RC 的长期可用状态投射到世界入口。
因此 RC 内容应沿“角色系列 launcher → 可用性/入口 → 正式任务 → 完成与下一段解锁”阅读。它可以使用与主线类似的任务和候选机制,但不能直接套用 RE 的种类冷却语义。
6. 在线事件多了资源和参与者协调#
net_random_event_launcher.sch 将客户端运行、主机运行、初始化、参与者循环拆开,主机维护入口会检查 NETWORK_IS_HOST_OF_THIS_SCRIPT。同时显式计算 peds、vehicles、objects 的事件预留和总预留,避免每个新事件都独立假定有无限网络对象额度。[S5]
具体内容通过 net_random_events.sch 提供触发资格、初始触发位置、范围和冷却等函数;例如幽灵车涉及目标玩家和冷却,其他事件涉及收集进度、场景位置或内容开关。[S6] 不同事件可以共享启动器而保留自己的筛选规则。
在线“SERVER”通常是脚本主机职责,不能据其命名推断这些函数运行在专用服务器。事件事实、选中的变体和关键实体应由会话内的权威状态保持;显示提示和本地参与判断则在各客户端处理。
7. 可复用的内容填充方法#
先定义内容槽位和变体,再定义什么时候不应该出现;把外围加载、真实触发、互动运行和回收分开;让成功、忽略与玩家破坏都有结束出口。对于多人,额外定义参与规则、网络实体额度、主机迁移后的状态来源和迟加入的可见结果。
不要把任务级例外误当成通用规则:RE_SIMEONYETARIAN、特定平台回归玩家事件、SeaPlane 的高度检查等有显式例外。本文描述本地分支,不推断全部发行版本都启用这些内容。
源码证据#
| 编号 | 位置 |
|---|---|
| [S1] | random_events_public.sch L190 解锁;L253 完成;L279 准入 |
| [S2] | random_event_private.sch L83 完成位;L98 冷却;L137 变体数量 |
| [S3] | re_bikethief.sc L317 场景;L739 盗窃;L1195 清理;L1235 主流程 |
| [S4] | RandomChar_Controller.sc L265 时间;L396 同地点;L555 地图揭示;L766 状态 |
| [S5] | net_random_event_launcher.sch L128 资源预算;L362 参与;L497 主机;L597 主机检查 |
| [S6] | net_random_events.sch L216 幽灵车目标;L313 冷却;L639 事件登记 |
[S1]: <../../../GTAV Source/script/dev_ng/singleplayer/include/public/random_events_public.sch> [S2]: <../../../GTAV Source/script/dev_ng/singleplayer/include/private/random_event_private.sch> [S3]: <../../../GTAV Source/script/dev_ng/singleplayer/scripts/Ambient/WorldPoint/re_bikethief.sc> [S4]: <../../../GTAV Source/script/dev_ng/singleplayer/scripts/RandomChar/RandomChar_Controller.sc> [S5]: <../../../GTAV Source/script/dev_ng/multiplayer/include/public/freemode/net_random_event_launcher.sch> [S6]: <../../../GTAV Source/script/dev_ng/multiplayer/include/public/freemode/net_random_events.sch>