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();
}
};
|