File: Script.c

package info (click to toggle)
openclonk 8.1-4
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 169,520 kB
  • sloc: cpp: 180,479; ansic: 108,988; xml: 31,371; python: 1,223; php: 767; makefile: 145; sh: 101; javascript: 34
file content (159 lines) | stat: -rw-r--r-- 5,094 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
/**
	Basic AI component for attacking enemies.

	@author Sven2, Maikel
*/

// Enemy spawn definition depends on this
local DefinitionPriority = 50;

// AI Settings.
local MaxAggroDistance = 200; // Lose sight to target if it is this far away (unless we're ranged - then always guard the range rect).
local GuardRangeX = 300; // Search targets this far away in either direction (searching in rectangle).
local GuardRangeY = 150; // Search targets this far away in either direction (searching in rectangle).

/*-- Public interface --*/


public func SetAllyAlertRange(object clonk, int new_range)
{
	AssertDefinitionContext(Format("SetAllyAlertRange(%v, %d)", clonk, new_range));
	var fx_ai = this->GetAI(clonk);
	if (!fx_ai)
		return false;
	fx_ai.ally_alert_range = new_range;
	return true;
}


// Set callback function name to be called in game script when this AI is first encountered
// Callback function first parameter is (this) AI clonk, second parameter is player clonk.
// The callback should return true to be cleared and not called again. Otherwise, it will be called every time a new target is found.
public func SetEncounterCB(object clonk, string cb_fn)
{
	AssertDefinitionContext(Format("SetEncounterCB(%v, %s)", clonk, cb_fn));
	var fx_ai = this->GetAI(clonk);
	if (!fx_ai)
		return false;
	fx_ai.encounter_cb = cb_fn;
	return true;
}


// Enable/disable auto-searching of targets.
public func SetAutoSearchTarget(object clonk, bool new_auto_search_target)
{
	AssertDefinitionContext(Format("SetAutoSearchTarget(%v, %v)", clonk, new_auto_search_target));
	var fx_ai = this->GetAI(clonk);
	if (!fx_ai)
		return false;
	fx_ai.auto_search_target = new_auto_search_target;
	return true;
}


// Set the guard range to the provided rectangle.
public func SetGuardRange(object clonk, int x, int y, int wdt, int hgt)
{
	AssertDefinitionContext(Format("SetGuardRange(%v, %d, %d, %d, %d)", clonk, x, y, wdt, hgt));
	var fx_ai = this->GetAI(clonk);
	if (!fx_ai)
		return false;
	// Clip to landscape size.
	if (x < 0)
	{
		wdt += x;
		x = 0;
	}
	if (y < 0)
	{
		hgt += y;
		y = 0;
	}
	wdt = Min(wdt, LandscapeWidth() - x);
	hgt = Min(hgt, LandscapeHeight() - y);
	fx_ai.guard_range = {x = x, y = y, wdt = wdt, hgt = hgt};
	return true;
}


// Set the maximum distance the enemy will follow an attacking clonk.
public func SetMaxAggroDistance(object clonk, int max_dist)
{
	AssertDefinitionContext(Format("SetMaxAggroDistance(%v, %d)", clonk, max_dist));
	var fx_ai = this->GetAI(clonk);
	if (!fx_ai)
		return false;
	fx_ai.max_aggro_distance = max_dist;
	return true;
}


/*-- Callbacks --*/

// Callback from the effect Construction()-call
public func OnAddAI(proplist fx_ai)
{
	_inherited(fx_ai);

	// Add AI default settings.
	SetGuardRange(fx_ai.Target, fx_ai.home_x - fx_ai.GuardRangeX, fx_ai.home_y - fx_ai.GuardRangeY, fx_ai.GuardRangeX * 2, fx_ai.GuardRangeY * 2);
	SetMaxAggroDistance(fx_ai.Target, fx_ai.MaxAggroDistance);
	SetAutoSearchTarget(fx_ai.Target, true);	
	
	// Store whether the enemy is controlled by a commander.
	fx_ai.commander = fx_ai.Target.commander;
}


// Callback from the Definition()-call
public func OnDefineAI(proplist def)
{
	_inherited(def);
	
	// Set the additional editor properties
	var additional_props =
	{
		ignore_allies = { Name = "$IgnoreAllies$", Type = "bool" },
		guard_range = { Name = "$GuardRange$", Type = "rect", Storage = "proplist", Color = 0xff00, Relative = false },
		max_aggro_distance = { Name = "$MaxAggroDistance$", Type = "circle", Color = 0x808080 },
		auto_search_target = { Name = "$AutoSearchTarget$", EditorHelp = "$AutoSearchTargetHelp$", Type = "bool" },
	};
	
	AddProperties(def->GetControlEffect().EditorProps, additional_props);
}


// Callback from the effect SaveScen()-call
public func OnSaveScenarioAI(proplist fx_ai, proplist props)
{
	_inherited(fx_ai, props);

	if (fx_ai.ally_alert_range)
		props->AddCall(SAVESCEN_ID_AI, fx_ai->GetControl(), "SetAllyAlertRange", fx_ai.Target, fx_ai.ally_alert_range);
	props->AddCall(SAVESCEN_ID_AI, fx_ai->GetControl(), "SetGuardRange", fx_ai.Target, fx_ai.guard_range.x, fx_ai.guard_range.y, fx_ai.guard_range.wdt, fx_ai.guard_range.hgt);
	if (fx_ai.max_aggro_distance != fx_ai->GetControl().MaxAggroDistance)
		props->AddCall(SAVESCEN_ID_AI, fx_ai->GetControl(), "SetMaxAggroDistance", fx_ai.Target, fx_ai.max_aggro_distance);
	if (!fx_ai.auto_search_target)
		props->AddCall(SAVESCEN_ID_AI, fx_ai->GetControl(), "SetAutoSearchTarget", fx_ai.Target, false);
	if (fx_ai.encounter_cb)
		props->AddCall(SAVESCEN_ID_AI, fx_ai->GetControl(), "SetEncounterCB", fx_ai.Target, Format("%v", fx_ai.encounter_cb));
}

/*-- Editor Properties --*/


// Gets an evaluator for the editor: Clonks
public func UserAction_EnemyEvaluator()
{
	var enemy_evaluator = UserAction->GetObjectEvaluator("IsClonk", "$Enemy$", "$EnemyHelp$");
	enemy_evaluator.Priority = 100;
	return enemy_evaluator;
}


// Gets an evaluator for the editor: Attack target
public func UserAction_AttackTargetEvaluator()
{
	return UserAction->GetObjectEvaluator("IsClonk", "$AttackTarget$", "$AttackTargetHelp$");
}