事件模组制作

本页面讲述的内容长期有效

事件是每个完善的模组的核心;是在游戏过程中可能发生在玩家身上的一系列或大或小的故事片段。

位置[编辑 | 编辑源代码]

事件属于位于Mod文件夹中的Events目录中的.txt文件。每个文件可以容纳任意多个事件。events目录也可以有包含自己事件文件的子文件夹(如果愿意的话)。

结构[编辑 | 编辑源代码]

整体结构与CK2的事件相似,语法进行了一些调整,并添加了大量的额外功能,其中许多是可选的。以下是最基本的事件(其中每个元素会在后面的小节中提到):

namespace = example
example.1 = {
	desc = example.1.desc
	
	option = {
		name = example.1.a
	}
}

好了!将这段代码添加到你的模组中,在游戏内控制台输入"event example.1"来触发它,你就会得到一个可用的事件!这就是一个最基本的事件结构,其他的内容都是可选的,但是它们在完善事件时是必须的。以下是一个更为详细的活动示例(仅包含基础内容):

## 这是一个基础事件,可将其作为其他事件的基础(参考)。不过,您可能希望先删除这段注释垃圾。
superexample.1337 = { # 请使用注释(比如这个!)在此处填写事件名称,这样其他模组编写者就可以在不知道ID的情况下找到你正在处理的事件。
	type = character_event
	title = "A Modding Example Worthy of Kings" # 专业提示:在编写时,你可以使用字符串,稍后再用本地化替换它。
	desc = birth.1003.b # 对于Sublime用户而言,有一个非常出色的功能,即“在文件中查找”,非常适用于查找代码。

	theme = mental_break
	left_portrait = root

	option = { # 在选项中使用注释来说明选项的内容或功能(例如:“不,我谴责你这个异端!”或“与孩子进行决斗”),这与事件标题的做法相似,这是一个很好的习惯。
		name = stewardship_domain_special.1424.a
	}
}

ID 和命名空间[编辑 | 编辑源代码]

命名空间(Namespaces)可以是任何由字母和数字组成的字符串(不包含'.'字符),并且用作前缀,形式为 <namespace>.<id>
ID是对于一个事件的唯一标识。
如果一个事件文件使用一个命名空间,那么它必须在文件开头声明 namespace = <namespace> 。对每个使用该命名空间的文件都需要进行声明。

旗帜[编辑 | 编辑源代码]

旗帜(Flags)是决定你的事件种类和外观的顶级变量。它们有一组有限的取值。

Flag 意义 可能的取值
type 事件的类型决定了根(root)的范围(scope)。
  • character_event
  • letter_event
  • none (当一个事件完全不使用作用域时)
  • empty (一个无角色事件必须的触发器。注意:这意味着输入 type = empty )
hidden 将此设置为true,事件将不会显示;它将在后台执行。适用于进行对玩家并不立即相关的维护事件。 true, false

人物肖像[编辑 | 编辑源代码]

在《十字军之王3》中,人物肖像是3D的,而且还有动画啦!肖像由不同的肖像位置列表和动画列表决定。

人物肖像定位[编辑 | 编辑源代码]

人物肖像效果
Portrait Position Description
left_portrait 在事件框的左侧显示肖像。
right_portrait 在事件框的右侧显示肖像。
lower_left_portrait 在事件框的左下方显示肖像。
lower_center_portrait 在事件框的正下方显示肖像。
lower_right_portrait 在事件框的右下方显示肖像。

这是一个同时使用所有人物肖像位置的示例,附效果截图:

example_event.1001 = {
	left_portrait = {
		character = ROOT # Whoever this is scoped to will show up in this event window position, exhibiting the chosen animation. 
		animation = fear # Take note that characters with SOME genetic traits (for example, gigantism, dwarfism) that change their character models have different animations, and if you assign one of THOSE animations to a character that does not have that model, crashes may occur.
	}
	right_portrait = {
		character = ROOT
		animation = scheme
	}
	lower_left_portrait = {
		character = ROOT
	}
	lower_center_portrait = {
		character = ROOT
	}
	lower_right_portrait = {
		character = ROOT
	}
}

肖像可以使用以下参数:

参数 描述 示例
character 展示哪个角色的肖像 character = scope:event_target
animation 角色将显示哪种动画 animation = anger
triggered_animation 如果符合条件,人物将显示这种动画。如果不符合,将显示以animation = 语句设置的动画。
triggered_animation = {
	trigger = {}
	animation = fear
}
triggered_outfit 设置事件中使用的服装
triggered_outfit = {
	trigger = {}
	outfit_tags = no_clothes (also accepts multiple tags, in the format outfit_tags = { tag1 tag2 }
	remove_default_outfit = yes/no
}
hide_info 避免显示人物的任何信息 (提示文字, 盾徽, clicks等). 只会显示人物肖像 hide_info = yes/no

人物动画[编辑 | 编辑源代码]

Animation
admiration aggressive_axe aggressive_dagger aggressive_hammer aggressive_mace aggressive_spear
aggressive_sword anger assassin beg boredom celebrate_axe
celebrate_dagger celebrate_hammer celebrate_mace celebrate_sword celebrate_spear chaplain
chancellor chess_certain_win chess_cocky disapproval disbelief disgust
dismissal drink drink_goblet eavesdrop ecstasy eyeroll
fear flirtation flirtation_left frontend_center_idle frontend_left_idle frontend_right_idle
grief happiness idle lantern laugh loss_1
love lunatic marshal newborn pain paranoia
personality_honorable personality_bold personality_callous personality_compassionate personality_content personality_coward
personality_cynical personality_dishonorable personality_forgiving personality_greedy personality_irrational personality_rational
personality_vengeful personality_zealous poison pregnant prisondungeon prisonhouse
rage sadness schadenfreude scheme severelywounded sick
shame shock spymaster steward stress test_case_1
throne_room_applaud_1 throne_room_bow_1 throne_room_bow_2 throne_room_bow_3 throne_room_chancellor throne_room_cheer_1
throne_room_cheer_2 throne_room_conversation_1 throne_room_conversation_2 throne_room_conversation_3 throne_room_conversation_4 throne_room_curtsey_1
throne_room_kneel_1 throne_room_kneel_2 throne_room_messenger_1 throne_room_messenger_2 throne_room_messenger_3 throne_room_one_handed_passive_1
throne_room_one_handed_passive_2 throne_room_ruler throne_room_two_handed_passive_1 throne_room_writer toast toast_goblet
war_attacker war_defender war_over_loss war_over_tie war_over_win worry

主题[编辑 | 编辑源代码]

主题(Themes)是一类用于角色肖像的背景、照明环境和音效的集合。它们在 common/event_themes/ 目录中声明。

Theme
abduct_scheme alliance bastardy battle
befriend_scheme claim_throne_scheme corruption crown
culture_change death default diplomacy
diplomacy_family_focus diplomacy_foreign_affairs_focus diplomacy_majesty_focus dread
dungeon dynasty education fabricate_hook_scheme
faith family feast_activity friend_relation
friendly generic_intrigue_scheme healthcare hunt_activity
hunting intrigue intrigue_intimidation_focus intrigue_skulduggery_focus
intrigue_temptation_focus learning learning_medicine_focus learning_scholarship_focus
learning_theology_focus love lover_relation marriage
martial martial_authority_focus martial_chivalry_focus martial_strategy_focus
medicine mental_break mental_health murder_scheme
party pet physical_health pilgrimage_activity
pregnancy prison realm recovery
rival_relation romance_scheme secret seduce_scheme
seduction skull stewardship stewardship_domain_focus
stewardship_duty_focus stewardship_wealth_focus sway_scheme unfriendly
vassal war witchcraft

可以使用 override_background, override_icon, override_sound, and override_environment 来覆盖主题的各个元素。

背景[编辑 | 编辑源代码]

Background
alley_day alley_night armory army_camp
battlefield bedchamber burning_building corridor_day
corridor_night council_chamber courtyard docks
dungeon farmland feast gallows
garden market market_east market_india
market_tribal market_west physicians_study sitting_room
study tavern temple temple_church
temple_generic temple_mosque temple_scope terrain
terrain_activity terrain_scope throne_room throne_room_east
throne_room_india throne_room_mediterranean throne_room_scope throne_room_tribal
throne_room_west wilderness wilderness_desert wilderness_forest
wilderness_forest_pine wilderness_mountains wilderness_scope wilderness_steppe

环境[编辑 | 编辑源代码]

当您选择了一个背景之后,系统会自动选择适当的环境。仅在必要时才进行更改。

Environment
environment_body environment_council environment_cw_east_main
environment_cw_east_spouse environment_cw_east_throneroom_main environment_cw_east_throneroom_spouse
environment_cw_india_main environment_cw_india_spouse environment_cw_india_throneroom_main
environment_cw_india_throneroom_spouse environment_cw_mediterranean_main environment_cw_mediterranean_spouse
environment_cw_mediterranean_throneroom_main environment_cw_mediterranean_throneroom_spouse environment_cw_tavern
environment_cw_tavern_spouse environment_cw_tribal_main environment_cw_tribal_spouse
environment_cw_west environment_cw_west_spouse environment_event_alley
environment_event_alley_day environment_event_armory environment_event_battlefield
environment_event_bedchamber environment_event_church environment_event_corridor_day
environment_event_courtyard environment_event_desert environment_event_docks
environment_event_dungeon environment_event_farms environment_event_feast
environment_event_forest environment_event_forest_pine environment_event_gallows
environment_event_garden environment_event_genericcamp environment_event_market_east
environment_event_market_tribal environment_event_market_west environment_event_mosque
environment_event_mountains environment_event_sittingroom environment_event_standard
environment_event_steppe environment_event_study environment_event_study_physician
environment_event_tavern environment_event_temple environment_event_throne_room_west
environment_frontend_east_heir environment_frontend_east_main environment_frontend_east_secondary
environment_frontend_india_heir environment_frontend_india_main environment_frontend_india_secondary
environment_frontend_mediterranean_heir environment_frontend_mediterranean_main environment_frontend_mediterranean_secondary
environment_frontend_tribal_heir environment_frontend_tribal_main environment_frontend_tribal_secondary
environment_frontend_west_heir environment_frontend_west_main environment_frontend_west_secondary
environment_head environment_hud environment_portrait_editor
environment_shoulders environment_standard environment_torso
environment_war_overview

触发器[编辑 | 编辑源代码]

这是一个事件达成所需要的额外要求。

trigger = { # 这是为了使这个事件成为可能所需的一系列要求(对于事件本身而言,这是一个巨大的IF语句)。
	culture = {
		has_innovation = innovation_guilds # 检查你的文化是否已解锁公会。
	}
}

还可以使用 trigger_if 将某些要求锁定在自己的触发器后面。
只有在 limit 为真时,才会执行 trigger_if 中的要求。如果 trigger_if 为假,可以选择添加 trigger_else 来执行备选要求。

trigger = {
	any_held_county = { # We check that we have a blacksmith
		any_county_province = {
			has_building_or_higher = blacksmiths_01
		}
	}

	trigger_if = { # 如果角色有贪婪的特质,需求增加500金币
		limit = { has_trait = greedy }
		gold > 500
	}
	trigger_else = { # 否则,必须至少拥有50点虔诚和10金币。
		piety > 50
        gold > 10
	}
}

触发失败[编辑 | 编辑源代码]

on_trigger_fail 在触发器无法触发时运行

描述[编辑 | 编辑源代码]

Description 解释如何组合多个字符串来构成描述,包括类似于first_valid和所有备选项的内容。

立即执行[编辑 | 编辑源代码]

Immediate 这是一个效果脚本块:当事件被触发时,它将立即运行,甚至在标题、描述和肖像被评估或渲染之前。这个脚本块适用于设置变量和保存作用域,以便在您的文本或肖像中使用;或者用于希望在玩家没有任何控制的情况下发生的功能性效果。

"has happened" 提示。

immediate = { # 无论选择哪个选项,当事件出现在屏幕上时,它都会起作用。
	add_gold = 50 # adds 50 gold to the player 
}

选项[编辑 | 编辑源代码]

在事件中,用户可以按下选项。每个事件可以有任意数量的选项,包括没有选项(一个常见的例子是隐藏事件)。每个选项在主事件块中定义,如下所示:

example.1 = {

	#[...]

	option = {
		# option info
	}

	#[...]

}

以下是一个更复杂的选项:修正

option = { # 选项名
	name = stewardship_domain_special.1424.a
	trigger_event = { # 让另一个事件发生
		id = yearly.1012 # 事件ID是访问级别最高的内容(因此,事件stewardship_domain.6017是有效的,只要它存在,任何其他事件也是有效的(valid))。
		days = { 7 14 } # 获取两个值之间的随机数(无法确定是否包括两个边界值),任何接受 "= {X Y}" 格式的内容也可以简化为 "= X"。
	}

	hidden_effect = { # 隐藏选项工具提示中的内容
		scope:county = { # 获取存储在作用域 "county" 中的内容。
			add_county_modifier = { # 添加修正(奖励或惩罚)
				modifier = governance_land_cleared_for_settlement_modifier 
                                # 确保使用正确的修正(在本例中为国家)。
				days = 3650 # 效果的持续时间,也可以用 days = {X Y}
			}
		}
	}

	ai_chance = {
		base = 50 # 选择这个选项相比其他选项的机会有多大?(不必是0到100,可以是任何数值)
		modifier = {  # 你可以根据各种因素来改变这个值,而在这种情况下,它是AI角色的特质。
			add = 15
			has_trait = sadistic # 特征可以在 ..\game\common\traits\00_traits.txt 中找到
		}
		modifier = {
			add = -40 # 要移除只需加上一个负数(5 + -10 = -5)。
			has_trait = compassionate
		}
	}
}

下表描述了 option 块中可用的键:

Key 必须 描述 例子
name 指向事件选项按钮文本的本地化键。 name=example.1.a
(effects) 选项可能产生的任何效果都可以直接写在 option 块中。 play_music_cue = mx_cue_banquet
trigger 定义了一个必须满足的触发器,以使选项有效并对用户可用。请注意,这与主要事件触发器不同。
trigger = {
	has_trait = shy
}
show_as_unavailable 如果选项无效,但触发器有效,则选项将显示但被禁用。此行为还受EVENT_OPTIONS_SHOWN_HIDE_UNAVAILABLE定义的影响。
show_as_unavailable = {
	short_term_gold < medium_gold_value
}
trait 如果玩家具有指定的特质,则在选项的左侧显示它。将鼠标悬停在上面时,会显示该选项可用的原因是由于该特质。这仅仅是为了增加趣味性,实际上并不影响选项的功能性。

trait = honest


skill 在选项的左侧显示所选技能。将鼠标悬停在其上会显示选项可用,因为你的技能水平较高。这只是为了增加趣味性,实际上并不影响选项的功能。

skill = prowess


add_internal_flag 可以取值为"特殊(special)"或"危险(dangerous)"。键值"特殊"将选项以黄色突出显示,"危险"则以红色突出显示。这只是提供一种风格,实际上并不影响选项的功能。

add_internal_flag = special


highlight_portrait 当将光标悬停在此选项上时,突出显示该角色的事件肖像。这是在悬停在具有影响角色肖像效果的事件选项上时自动高亮显示的附加功能。 highlight_portrait = scope:custom
fallback 等于是(yes)的时候:如果没有其他选项满足其触发器,即使此选项的触发条件也未满足,它也将显示出来。你可以将此选项与 trigger = { always = no } 结合使用,以创建一个只作为最后手段显示的选项。 fallback = yes
exclusive 如果选项标记为exclusive = yes并且符合其触发条件,它将是唯一显示的选项。如果多个选项标记为exclusive = yes并且每个选项都符合其触发条件,那么每个选项都会被显示。 exclusive = yes
flavor 在选项的工具提示中显示的风味文本。风味可以是本地化键(loc key)或具有first_valid等的动态描述。 flavor = my_events.1001.a.flavor

后处理[编辑 | 编辑源代码]

After 这是一个在事件完成并选择了一个选项后运行的效果脚本块。与#Immediate脚本块完全相同。如果事件没有选项(例如隐藏事件),则不会执行任何操作。
它最常用于清理任务,删除可能会在不打算时持续存在的变量、字符和其他类型的数据。
举个例子,在事件 fp2_struggle.2009 《抓到神秘盗贼》(Catching Thieves of Myth) 中,after块用于检查是否有保存的范围(用作布尔值),以决定在事件结束后是否应该删除事件生成的角色。

after = {
	if = {
		limit = { NOT = { exists = scope:fp2_2009_thief_permanence_scope } } # 如果存在,则作为布尔值为真
		scope:fp2_2009_garduna_young_thief = { silent_disappearance_effect = yes } # 我们将年轻的小偷除掉,因为他对未来的事态已经不再有用。
	}
}

部件[编辑 | 编辑源代码]

Widgets 有哪些部件,并给出截图

触发动作 (on_action)[编辑 | 编辑源代码]

On Actions(触发动作)是游戏代码调用时,每次执行特定动作(如孩子出生、角色继承土地或使用牵制)时运行的脚本。
这允许模组制作者在调用相关的"On Actions"时,拦截并运行自己的脚本。
触发动作分为两个主要类型:

  1. 从代码中调用的内容。
  2. 脚本中调用的内容。

这些 on_action 脚本有一点奇怪,因为它不允许追加效果和触发器,这使得创建一个具有良好兼容性的模组变得不可能。然而,你可以通过以下方式实现类似的效果:

on_birth_child = { 
	on_actions = { # "on_action" 内的 "on_actions" 已经被追加,因此可以安全地使用下面表格中的现有 on_action。
		on_action_my_on_action 
	} 
} 
on_action_my_on_action = { 
	trigger = { ... } 
	effect = {... } 
}

如果您编写的脚本如下所示,触发器和效果将不会追加,因此在修改相同的 on_actions 的模组之间可能会发生冲突:

on_birth_child = { # 下表中的一个 on_action 
	trigger = { ... } 
	effect = {... } # 触发和效果被覆盖,而非追加。 
}

on_actions中的变量[编辑 | 编辑源代码]

表格中的内容来自 /common/on_action/on_actions.info 文件.

名称 描述 可能的数据类型 例子
trigger on_actions可以有触发器。如果一个on_action触发并且其触发器返回false,则什么都不会发生。 boolean
trigger = {
	trigger_conditions = yes
}
weight_multiplier 如果此项是随机动作列表中的候选项(请参见下文),则用于操作其权重。 integer
weight_multiplier = {
	base = 1
	modifier = {
		add = 1
		trigger_conditions = yes
	}
}
events 只要触发器的返回结果为真,"events"括号中列出的事件将会触发。
events = {
	event_id_1
	delay = { days = 365 }		# 延迟意味着在延迟时间过去之后,所有列在其后的事件才会被触发。 注意:出于性能原因,只有在 on_action 执行时以及延迟完成后,事件才能成功触发。所有的触发条目都支持延迟,无论是用于事件还是 on_action。
	event_id_2
	delay = { months = { 6 12 } }	# 设置新的延迟会覆盖之前的延迟。延迟支持随机范围。
	event_id_3
}
random_events 选择一个事件进行触发。
random_events = {	# 选择一个事件进行触发。
		
	chance_to_happen = 25	# 一个几率决定是否会对所涉及的事件进行评估

	chance_of_no_event = { 	# 一个可以格式化为脚本值的条目(因此可以具有条件条目)。出于性能原因,与“chance_to_happen”分开。仅在chance_to_happen为true时进行评估。
		value = 0
		if = {
			limit = { trigger_conditions = yes }
			add = 10
		}
	}

	100 = event_id_1 	# 数字是选择特定事件的权重。该权重受到事件的weight_multiplier条目的影响。(如果事件没有定义weight_multiplier,权重将为1)
	200 = event_id_2
	100 = 0		# 如果一个事件的条目为“0”,即使存在其他有效的事件,也有可能没有事件触发。这对于确保罕见事件不总是触发非常重要,因为其他可能的事件都无效。

}
first_valid 选择第一个使触发器返回 true 的事件。 List<event>
first_valid = {		# 选择第一个使触发器返回 true 的事件。
	event_id_1
	event_id_2
	fallback_event_without_trigger
}
on_actions 一个 on_action 可以触发其他 on_action,遵循与事件相同的规则。 List<on_action>
on_actions = {	#一个 on_action 可以触发其他 on_action,遵循与事件相同的规则。
	on_action_1
	on_action_2
	on_action_3
}
random_on_actions 就像事件一样,对于on_actions,它们也受其weight_multipliers的影响,该值默认为1。
random_on_actions = {
	100 = on_action_1
	200 = on_action_2
	100 = 0
}
first_valid_on_action List<on_action> <syntaxhighlight>

first_valid_on_action = { on_action_1 on_action_2 }

effect on_action可以运行效果(effect)。它可以访问与触发它的脚本链/代码功能相同的默认(default)范围或保存(saved)范围(scope)。请注意,它与on_action触发的事件同时发生,而不是在之前。此处运行的效果会创建一个与on_action触发的事件不同的链,因此您不能在效果中操作值,然后可靠地在同时触发的事件中访问这些值。在这里设置的范围或局部变量不会传递到由on_action触发的任何事件。
effect = {
	effects = yes
}

fallback on_actions 可以定义一个回退 on_action。如果没有事件或 on_actions 被 on_action 运行,就会调用回退。避免创建无限回退循环,否则可能会阻止游戏时间的推进! on_action
fallback = another_on_action


来自代码的 On_actions[编辑 | 编辑源代码]

名称 描述 From code 预计作用域 其他
on_prestige_level_loss Yes None
on_rank_down Yes None
on_weight_changed Yes Character
on_faith_monthly Yes Faith
on_knight_combat_pulse Yes Character
on_war_invalidated Yes None
on_war_transferred Yes Character
on_divorce Yes None
on_leave_court Yes Character
on_guest_ready_to_move_to_pool Yes Character
on_guest_arrived_from_pool Yes Character
on_siege_completion Yes Character
on_war_won_attacker Yes Casus belli
on_alliance_added Yes None
on_pregnancy_mother Yes Character
on_raid_action_start Yes None
on_county_faith_change Yes Landed Title
on_title_gain_usurpation Yes None
on_release_from_prison Yes Character
random_yearly_playable_pulse Yes Character
on_raid_action_completion Yes Army
on_death Yes Character
on_birth_father Yes None
on_betrothal_broken Yes None
on_war_white_peace Yes None
three_year_playable_pulse Yes Character
on_defeat_raid_army Yes Army
on_army_enter_province Yes Character
on_join_court Yes Character
on_fired_from_council Yes Character
on_raid_loot_delivered Yes Army
on_pregnancy_ended_mother Yes None
on_title_lost Yes None
on_title_gain Yes Character
on_character_culture_change Yes Character
on_birth_child Yes Character
on_holy_order_hired Yes None
on_great_holy_war_invalidation Yes Great Holy War
on_combat_end_loser Yes Combat Side
on_concubinage Yes None
on_commander_combat_pulse Yes Character
random_yearly_everyone_pulse Yes Character
five_year_everyone_pulse Yes Character
on_perks_refunded Yes None
quarterly_playable_pulse Yes None
on_prestige_level_gain Yes None
on_faith_created Yes Character
on_holy_order_new_lease Yes None
on_title_gain_inheritance Yes None
on_game_start Yes None
on_character_faith_change Yes Character
on_combat_end_winner Yes Combat Side
on_courtier_decided_to_move_to_pool Yes Character
on_culture_era_changed Yes None
on_birthday Yes Character
on_faith_conversion Yes Character
on_raid_action_weekly Yes None
on_explicit_claim_gain Yes Character
on_courtier_ready_to_move_to_pool Yes Character
on_potential_great_holy_war_invalidation Yes Great Holy War
on_holy_order_destroyed Yes None
on_war_won_defender Yes Casus belli
yearly_global_pulse Yes None
on_great_holy_war_countdown_end Yes GreaT Holy War
yearly_playable_pulse Yes Character
three_year_pool_pulse Yes Character
on_pregnancy_father Yes None
on_piety_level_loss Yes None
on_piety_level_gain Yes None
on_siege_looting Yes None
on_title_destroyed Yes None
on_army_monthly Yes None
on_game_start_after_lobby Yes None
on_imprison Yes Character
on_birth_mother Yes Character
on_dynasty_created Yes None
on_alliance_removed Yes None
on_county_occupied Yes None
on_rank_up Yes None
on_vassal_become_powerful Yes None
on_join_war_as_secondary Yes Character
on_explicit_claim_lost Yes Character
on_alliance_broken Yes None
on_natural_death_second_chance Yes None
on_leave_council Yes Character
on_county_culture_change Yes None
on_war_started Yes None
on_marriage Yes Character
on_great_holy_war_participant_replaced Yes Character
five_year_playable_pulse Yes Character
on_birth_real_father Yes None
on_game_start_with_tutorial Yes None

脚本中的On_actions[编辑 | 编辑源代码]

策略[编辑 | 编辑源代码]

触发事件[编辑 | 编辑源代码]

Should probably become its own page.

Techniques and design patterns[编辑 | 编辑源代码]

Pinging events, message events.

Other fancy ideas.