File: Script.c

package info (click to toggle)
openclonk 8.1-2
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 169,500 kB
  • sloc: cpp: 180,478; ansic: 108,988; xml: 31,371; python: 1,223; php: 767; makefile: 139; sh: 101; javascript: 34
file content (198 lines) | stat: -rw-r--r-- 5,015 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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
/**
	Library_Wearable
	Library for all clothing and other things worn on the clonk.
	The library will make sure that not two objects are worn at the same
	position at the same time.
	
	@author: Clonkonaut
*/

/* Bone names of attachment on the clonk and also identifiers */

// Headwear like helmets, caps or similar
static const WEARABLE_Head = "skeleton_head";

local wear_effect;

local display_disabled = false;

/* Overloads */

// These functions must exist in order for this library to work

public func GetWearPlace()
{
	return; // must return one of the WEARABLE_* constants
}

/* Other functions that can be present in the object:

func GetWearBone: return the bone with which it is attached to the clonk (default: "main")
func GetWearTransform(clonk): transformation added when worn

func StayAfterDeath: return true if the item should remain on the clonk after its death (default is that it does not stay)

func OnPutOn(clonk): callback after the item was put on
func OnTakenOff(clonk): callback after the item was taken off

func OnDamage(damage_amount, cause, by_player): Callback whenever the wearer is damaged, parameters are passed on from the effect Damage callback
                                                Return value is returned (useful for protective clothing)

func GetCarryMode: must(!) return CARRY_None whenever display_disabled is true, otherwise display error will likely occur

*/

/* Engine Callbacks */

// It is assumed that a wearable must be contained in the clonk to be worn.
public func Departure()
{
	if (IsWorn())
		TakeOff();
	_inherited(...);
}

public func Destruction()
{
	if (IsWorn())
		TakeOff();
	_inherited(...);
}

/* Interface */

// The clonk will put on the item and take off any other item currently worn
// in the same place, unless no_force is true in which case false will be returned
// when something else is worn.
public func PutOn(object clonk, bool no_force)
{
	// ???
	if (!clonk->~IsClonk()) return false;

	// Remove all other things before putting on
	if (!no_force)
	{
		var fx;
		for (var i = GetEffectCount("FxWearing", clonk); fx = GetEffect("FxWearing", clonk, i - 1); i--)
			if (fx.identifier == GetWearPlace())
				fx->Remove();
	}

	// It is not impossible that the item is currently held in the hand of the clonk.
	// If so, temporarily disable display because the same mesh cannot be attached twice.
	// Any item must adhere this variable in GetCarryMode!
	display_disabled =true;
	clonk->~UpdateAttach();

	wear_effect = clonk->CreateEffect(FxWearing, 2, nil, GetWearPlace(), this);

	if (wear_effect == -1) // got rejected
		wear_effect = nil;

	display_disabled = false;
	clonk->~UpdateAttach();

	if (wear_effect)
	{
		// Callback to do whatever
		this->~OnPutOn(clonk);
		return true;
	}

	return false;
}

public func IsWorn()
{
	return wear_effect;
}

public func TakeOff()
{
	if (wear_effect)
		wear_effect->Remove();
	return;
}

public func TakenOff()
{
	wear_effect = nil;
	if (Contained())
		Contained()->~UpdateAttach();
	// Callback to do whatever; note that at this point the item isn't necessary contained.
	this->~OnTakenOff();
}

// Returns whether the clonk has a free place for this wearable.
public func HasFreeWearPlace(object clonk)
{
	var fx;
	for (var i = GetEffectCount("FxWearing", clonk); fx = GetEffect("FxWearing", clonk, i - 1); i--)
		if (fx.identifier == GetWearPlace())
			return false;
	return true;
}

public func IsWearable() { return true; }

/* Wearing effect */

local FxWearing = new Effect {
	Construction = func(string wearing_identifier, object worn_item)
	{
		// Save where this thing is worn
		this.identifier = wearing_identifier;
		// Save what is worn
		this.item = worn_item;
	},

	Start = func()
	{
		// Check if parameters are properly set
		if (this.identifier == nil) return -1;
		if (this.item == nil) return -1;

		var attachment_bone = this.item->~GetWearBone() ?? "main";
		var attachment_transform = this.item->~GetWearTransform(this.Target);
		var attachment_flags = this.item->~GetWearFlags(); // does not need a default value

		this.attach = Target->AttachMesh(this.item, this.identifier, attachment_bone, attachment_transform, attachment_flags);
	},

	Damage = func(int damage, int cause, int by_player)
	{
		if (!this.item) return damage;

		var ret = this.item->~OnDamage(damage, cause, by_player);
		if (ret == nil)
			ret = damage;
		return ret;
	},

	Effect = func(string new_name, var1)
	{
		// Reject wearing effects if in the same place
		if (new_name == "FxWearing")
			if (var1 == this.identifier)
				return -1;
	},

	Stop = func(int reason)
	{
		// Items can prevent being removed from the clonk on death
		if (reason == FX_Call_RemoveDeath)
			if (this.item && this.item->~StayAfterDeath(this.Target))
				return -1;

		if (this.Target) this.Target->DetachMesh(this.attach);
		this.attach = nil;
	},

	Destruction = func()
	{
		if (this.attach != nil && this.Target)
			this.Target->DetachMesh(this.attach);
		if (this.item)
			this.item->TakenOff();
	}
};