2009-12-29 13:44:16 +00:00
|
|
|
/*
|
|
|
|
Standard clonk controls
|
|
|
|
Author: Newton
|
|
|
|
|
|
|
|
This object provides handling of the clonk controls including item
|
2010-04-09 15:06:28 +00:00
|
|
|
management, backpack controls and standard throwing behaviour. It
|
2010-08-19 11:17:43 +00:00
|
|
|
should be included into any clonk/crew definition.
|
2011-03-13 15:16:45 +00:00
|
|
|
The controls in System.ocg/PlayerControl.c only provide basic movement
|
2009-12-29 13:44:16 +00:00
|
|
|
handling, namely the movement left, right, up and down. The rest is
|
|
|
|
handled here:
|
|
|
|
Grabbing, ungrabbing, shifting and pushing vehicles into buildings;
|
2010-04-09 15:06:28 +00:00
|
|
|
entering and exiting buildings; throwing, dropping; backpack control,
|
|
|
|
(object) menu control, hotkey controls, usage and it's callbacks and
|
|
|
|
forwards to script. Also handled by this library is the aiming with
|
|
|
|
the gamepad conrols.
|
2009-12-29 13:44:16 +00:00
|
|
|
|
|
|
|
Objects that inherit this object need to return _inherited() in the
|
|
|
|
following callbacks (if defined):
|
|
|
|
Construction, Collection2, Ejection, RejectCollect, Departure,
|
2010-08-19 11:17:43 +00:00
|
|
|
Entrance, AttachTargetLost, CrewSelection, Death,
|
|
|
|
Destruction, OnActionChanged
|
2010-03-30 16:48:38 +00:00
|
|
|
|
2009-12-29 13:44:16 +00:00
|
|
|
The following callbacks are made to other objects:
|
|
|
|
*Stop
|
|
|
|
*Left, *Right, *Up, *Down
|
2010-04-09 15:06:28 +00:00
|
|
|
*Use, *UseStop, *UseStart, *UseHolding, *UseCancel
|
2009-12-29 13:44:16 +00:00
|
|
|
wheras * is 'Contained' if the clonk is contained and otherwise (riding,
|
2010-09-13 15:27:48 +00:00
|
|
|
pushing, to self) it is 'Control'. The item in the inventory only gets
|
2009-12-29 13:44:16 +00:00
|
|
|
the Use*-calls. If the callback is handled, you should return true.
|
2010-04-09 15:06:28 +00:00
|
|
|
Currently, this is explained more in detail here:
|
|
|
|
http://forum.openclonk.org/topic_show.pl?tid=337
|
2009-12-29 13:44:16 +00:00
|
|
|
|
|
|
|
The inventory management:
|
|
|
|
The objects in the inventory are saved (parallel to Contents()) in the
|
2010-05-08 00:02:17 +00:00
|
|
|
array 'inventory'. They are accessed via GetItem(i) and GetItemPos(obj).
|
2009-12-29 13:44:16 +00:00
|
|
|
Other functions are MaxContentsCount() (defines the maximum number of
|
2010-05-08 00:02:17 +00:00
|
|
|
contents)
|
2009-12-29 13:44:16 +00:00
|
|
|
*/
|
|
|
|
|
2010-03-25 23:56:55 +00:00
|
|
|
/* ++++++++++++++++++++++++ Clonk Inventory Control ++++++++++++++++++++++++ */
|
|
|
|
|
2010-02-18 21:22:58 +00:00
|
|
|
local indexed_inventory;
|
|
|
|
local disableautosort;
|
2011-08-11 14:37:46 +00:00
|
|
|
local force_collection;
|
2010-02-18 21:22:58 +00:00
|
|
|
local inventory;
|
|
|
|
|
2009-12-29 13:44:16 +00:00
|
|
|
/* Item limit */
|
|
|
|
|
2010-03-26 13:50:00 +00:00
|
|
|
private func HandObjects() { return 2; }
|
2010-04-29 01:55:44 +00:00
|
|
|
public func MaxContentsCount() { return 7; }
|
2009-12-29 13:44:16 +00:00
|
|
|
|
2010-03-25 23:56:55 +00:00
|
|
|
/* Get the ith item in the inventory */
|
2010-05-08 00:02:17 +00:00
|
|
|
// the first two are in the hands
|
2009-12-29 13:44:16 +00:00
|
|
|
public func GetItem(int i)
|
|
|
|
{
|
2010-05-08 00:02:17 +00:00
|
|
|
if (i >= GetLength(inventory))
|
|
|
|
return nil;
|
2011-08-11 14:37:46 +00:00
|
|
|
if (i < 0) return nil;
|
2010-05-08 00:02:17 +00:00
|
|
|
|
2009-12-29 13:44:16 +00:00
|
|
|
return inventory[i];
|
|
|
|
}
|
|
|
|
|
2011-09-04 17:42:43 +00:00
|
|
|
// For the HUD: this object shows its items in the HUD (i.e. has the GetItem function)
|
|
|
|
public func HUDShowItems() { return true; }
|
|
|
|
|
2010-03-25 23:56:55 +00:00
|
|
|
/* Search the index of an item */
|
|
|
|
|
2009-12-30 15:50:25 +00:00
|
|
|
public func GetItemPos(object item)
|
|
|
|
{
|
2010-02-02 15:09:56 +00:00
|
|
|
if (item)
|
|
|
|
if (item->Contained() == this)
|
2009-12-30 15:50:25 +00:00
|
|
|
{
|
|
|
|
var i = 0;
|
|
|
|
for(var obj in inventory)
|
|
|
|
{
|
2010-02-02 15:09:56 +00:00
|
|
|
if (obj == item) return i;
|
2009-12-30 15:50:25 +00:00
|
|
|
++i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
2010-03-25 23:56:55 +00:00
|
|
|
/* Switch two items in the clonk's inventory */
|
|
|
|
|
2009-12-30 15:50:25 +00:00
|
|
|
public func Switch2Items(int one, int two)
|
|
|
|
{
|
2010-03-25 23:56:55 +00:00
|
|
|
// no valid inventory index: cancel
|
2011-05-12 15:01:54 +00:00
|
|
|
if (!Inside(one,0,MaxContentsCount()-1)) return;
|
|
|
|
if (!Inside(two,0,MaxContentsCount()-1)) return;
|
2010-02-15 20:51:26 +00:00
|
|
|
|
2010-03-25 23:56:55 +00:00
|
|
|
// switch them around
|
2009-12-30 15:50:25 +00:00
|
|
|
var temp = inventory[one];
|
|
|
|
inventory[one] = inventory[two];
|
|
|
|
inventory[two] = temp;
|
|
|
|
|
2010-03-25 23:56:55 +00:00
|
|
|
// callbacks: cancel use
|
2010-02-02 15:09:56 +00:00
|
|
|
if (using == inventory[one] || using == inventory[two])
|
2010-01-22 16:29:46 +00:00
|
|
|
CancelUse();
|
|
|
|
|
2010-03-25 23:56:55 +00:00
|
|
|
// callbacks: (de)selection
|
2010-05-08 00:02:17 +00:00
|
|
|
if (one < HandObjects())
|
|
|
|
if (inventory[two]) inventory[two]->~Deselection(this,one);
|
|
|
|
if (two < HandObjects())
|
|
|
|
if (inventory[one]) inventory[one]->~Deselection(this,two);
|
|
|
|
|
|
|
|
if (one < HandObjects())
|
|
|
|
if (inventory[one]) inventory[one]->~Selection(this,one);
|
|
|
|
if (two < HandObjects())
|
|
|
|
if (inventory[two]) inventory[two]->~Selection(this,two);
|
2010-01-12 21:06:20 +00:00
|
|
|
|
2010-03-25 23:56:55 +00:00
|
|
|
// callbacks: to self, for HUD
|
2010-03-26 13:50:00 +00:00
|
|
|
if (one < HandObjects())
|
2010-03-25 23:56:55 +00:00
|
|
|
{
|
|
|
|
if (inventory[one])
|
|
|
|
this->~OnSlotFull(one);
|
|
|
|
else
|
|
|
|
this->~OnSlotEmpty(one);
|
|
|
|
}
|
2010-03-26 13:50:00 +00:00
|
|
|
if (two < HandObjects())
|
2010-03-25 23:56:55 +00:00
|
|
|
{
|
|
|
|
if (inventory[two])
|
|
|
|
this->~OnSlotFull(two);
|
|
|
|
else
|
|
|
|
this->~OnSlotEmpty(two);
|
|
|
|
}
|
2009-12-30 15:50:25 +00:00
|
|
|
}
|
|
|
|
|
2010-03-25 23:56:55 +00:00
|
|
|
/* Overload of Collect function */
|
|
|
|
|
2011-08-11 14:37:46 +00:00
|
|
|
public func Collect(object item, bool ignoreOCF, int pos, bool force)
|
2009-12-30 15:50:25 +00:00
|
|
|
{
|
2011-08-11 14:37:46 +00:00
|
|
|
force_collection = force;
|
|
|
|
var success = false;
|
|
|
|
if (pos == nil)
|
|
|
|
{
|
|
|
|
success = _inherited(item,ignoreOCF);
|
|
|
|
force_collection = false;
|
|
|
|
return success;
|
|
|
|
}
|
2009-12-30 15:50:25 +00:00
|
|
|
// fail if the specified slot is full
|
2011-08-11 14:37:46 +00:00
|
|
|
if (GetItem(pos) == nil)
|
2009-12-30 15:50:25 +00:00
|
|
|
{
|
2011-08-11 14:37:46 +00:00
|
|
|
if (item)
|
|
|
|
{
|
|
|
|
pos = BoundBy(pos,0,MaxContentsCount()-1);
|
|
|
|
|
|
|
|
disableautosort = true;
|
|
|
|
// collect but do not sort in_
|
|
|
|
// Collection2 will be called which attempts to automatically sort in
|
|
|
|
// the collected item into the next free inventory slot. Since 'pos'
|
|
|
|
// is given as a parameter, we don't want that to happen and sort it
|
|
|
|
// in manually afterwards
|
|
|
|
var success = _inherited(item);
|
|
|
|
disableautosort = false;
|
|
|
|
if (success)
|
|
|
|
{
|
|
|
|
inventory[pos] = item;
|
|
|
|
if (pos < HandObjects())
|
|
|
|
this->~OnSlotFull(pos);
|
|
|
|
}
|
|
|
|
}
|
2009-12-30 15:50:25 +00:00
|
|
|
}
|
2011-08-11 14:37:46 +00:00
|
|
|
|
|
|
|
force_collection = false;
|
2009-12-30 15:50:25 +00:00
|
|
|
return success;
|
|
|
|
}
|
|
|
|
|
2011-03-13 15:55:00 +00:00
|
|
|
// disable ShiftContents for objects with ClonkControl.ocd
|
2009-12-29 13:44:16 +00:00
|
|
|
|
|
|
|
global func ShiftContents()
|
|
|
|
{
|
|
|
|
if (this)
|
2010-05-08 00:02:17 +00:00
|
|
|
if (this->~HandObjects() != nil)
|
2009-12-29 13:44:16 +00:00
|
|
|
return false;
|
|
|
|
return _inherited(...);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ################################################# */
|
|
|
|
|
|
|
|
protected func Construction()
|
|
|
|
{
|
2010-03-23 20:57:30 +00:00
|
|
|
menu = nil;
|
2010-03-25 23:56:55 +00:00
|
|
|
|
|
|
|
// inventory variables
|
2010-02-18 21:22:58 +00:00
|
|
|
indexed_inventory = 0;
|
2010-03-25 23:56:55 +00:00
|
|
|
inventory = CreateArray();
|
|
|
|
|
2011-08-11 14:37:46 +00:00
|
|
|
force_collection = false;
|
|
|
|
|
2010-03-25 23:56:55 +00:00
|
|
|
// using variables
|
2009-12-29 13:44:16 +00:00
|
|
|
alt = false;
|
|
|
|
using = nil;
|
2010-10-09 17:08:58 +00:00
|
|
|
using_type = nil;
|
2010-03-25 23:56:55 +00:00
|
|
|
|
2010-12-08 00:56:48 +00:00
|
|
|
backpack_open = false;
|
|
|
|
|
2009-12-29 13:44:16 +00:00
|
|
|
return _inherited(...);
|
|
|
|
}
|
|
|
|
|
|
|
|
protected func Collection2(object obj)
|
|
|
|
{
|
2010-06-25 17:06:59 +00:00
|
|
|
var sel = 0;
|
2009-12-29 13:44:16 +00:00
|
|
|
|
2010-03-25 23:56:55 +00:00
|
|
|
// See Collect()
|
2010-02-02 15:09:56 +00:00
|
|
|
if (disableautosort) return _inherited(obj,...);
|
2009-12-30 15:50:25 +00:00
|
|
|
|
2010-02-25 12:14:00 +00:00
|
|
|
var success = false;
|
|
|
|
|
2009-12-29 13:44:16 +00:00
|
|
|
// into selected area if empty
|
2010-05-08 00:02:17 +00:00
|
|
|
if (!inventory[0])
|
2009-12-29 13:44:16 +00:00
|
|
|
{
|
2010-05-08 00:02:17 +00:00
|
|
|
inventory[0] = obj;
|
2010-02-25 21:46:05 +00:00
|
|
|
success = true;
|
2009-12-29 13:44:16 +00:00
|
|
|
}
|
|
|
|
// otherwise, next if empty
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for(var i = 1; i < MaxContentsCount(); ++i)
|
|
|
|
{
|
2010-05-08 00:02:17 +00:00
|
|
|
sel = i % MaxContentsCount();
|
2009-12-29 13:44:16 +00:00
|
|
|
if (!inventory[sel])
|
|
|
|
{
|
2010-02-18 21:22:58 +00:00
|
|
|
indexed_inventory++;
|
2009-12-29 13:44:16 +00:00
|
|
|
inventory[sel] = obj;
|
2010-02-25 12:14:00 +00:00
|
|
|
success = true;
|
2009-12-29 13:44:16 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-03-25 23:56:55 +00:00
|
|
|
// callbacks
|
2010-03-03 18:02:47 +00:00
|
|
|
if (success)
|
2010-03-26 13:50:00 +00:00
|
|
|
if (sel < HandObjects())
|
|
|
|
this->~OnSlotFull(sel);
|
2010-01-12 22:30:25 +00:00
|
|
|
|
2010-05-08 00:02:17 +00:00
|
|
|
if (sel == 0 || sel == 1)
|
|
|
|
obj->~Selection(this,sel == 1);
|
2009-12-29 13:44:16 +00:00
|
|
|
|
|
|
|
return _inherited(obj,...);
|
|
|
|
}
|
|
|
|
|
|
|
|
protected func Ejection(object obj)
|
|
|
|
{
|
2010-03-25 23:56:55 +00:00
|
|
|
// if an object leaves this object
|
|
|
|
|
2010-01-22 16:29:46 +00:00
|
|
|
// find obj in array and delete (cancel using too)
|
2010-02-25 12:14:00 +00:00
|
|
|
var i = 0;
|
|
|
|
var success = false;
|
|
|
|
for(var item in inventory)
|
2009-12-29 13:44:16 +00:00
|
|
|
{
|
2010-09-13 15:27:48 +00:00
|
|
|
if (obj == item)
|
2010-01-22 16:29:46 +00:00
|
|
|
{
|
|
|
|
inventory[i] = nil;
|
2010-02-18 21:22:58 +00:00
|
|
|
indexed_inventory--;
|
2010-02-25 12:14:00 +00:00
|
|
|
success = true;
|
2010-01-22 16:29:46 +00:00
|
|
|
break;
|
|
|
|
}
|
2010-02-25 12:14:00 +00:00
|
|
|
++i;
|
2009-12-29 13:44:16 +00:00
|
|
|
}
|
2010-02-02 15:09:56 +00:00
|
|
|
if (using == obj) CancelUse();
|
2010-02-25 12:14:00 +00:00
|
|
|
|
2010-03-25 23:56:55 +00:00
|
|
|
// callbacks
|
2010-03-26 13:50:00 +00:00
|
|
|
if (success)
|
|
|
|
if (i < HandObjects())
|
|
|
|
this->~OnSlotEmpty(i);
|
2009-12-29 13:44:16 +00:00
|
|
|
|
2010-05-08 00:02:17 +00:00
|
|
|
if (i == 0 || i == 1)
|
|
|
|
obj->~Deselection(this,i == 1);
|
2010-01-12 22:30:25 +00:00
|
|
|
|
2010-03-25 23:56:55 +00:00
|
|
|
// we have over-weight? Put the next unindexed object inside that slot
|
|
|
|
// this happens if the clonk is stuffed full with items he can not
|
|
|
|
// carry via Enter, CreateContents etc.
|
2010-03-03 18:02:47 +00:00
|
|
|
if (ContentsCount() > indexed_inventory && !inventory[i])
|
2010-02-18 21:22:58 +00:00
|
|
|
{
|
2010-03-25 23:56:55 +00:00
|
|
|
for(var c = 0; c < ContentsCount(); ++c)
|
2010-02-18 21:22:58 +00:00
|
|
|
{
|
2010-03-03 18:02:47 +00:00
|
|
|
if (GetItemPos(Contents(c)) == nil)
|
2010-02-18 21:22:58 +00:00
|
|
|
{
|
|
|
|
// found it! Collect it properly
|
|
|
|
inventory[i] = Contents(c);
|
|
|
|
indexed_inventory++;
|
|
|
|
|
2010-03-26 13:50:00 +00:00
|
|
|
if (i < HandObjects())
|
|
|
|
this->~OnSlotFull(i);
|
2010-02-18 21:22:58 +00:00
|
|
|
|
2010-05-08 00:02:17 +00:00
|
|
|
if (i == 0 || i == 1)
|
|
|
|
Contents(c)->~Selection(this,i == 1);
|
2010-02-18 21:22:58 +00:00
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-12-29 13:44:16 +00:00
|
|
|
_inherited(obj,...);
|
|
|
|
}
|
|
|
|
|
|
|
|
protected func RejectCollect(id objid, object obj)
|
|
|
|
{
|
2010-09-20 16:17:53 +00:00
|
|
|
// collection of that object magically disabled?
|
|
|
|
if(GetEffect("NoCollection", obj)) return true;
|
2011-10-26 21:03:12 +00:00
|
|
|
|
|
|
|
//No collection if the clonk is carrying a 'carry-heavy' object
|
|
|
|
if(GetEffect("IntCarryHeavy", this) || GetEffect("IntLiftHeavy", this)) return true;
|
2010-09-20 16:17:53 +00:00
|
|
|
|
2010-03-25 23:56:55 +00:00
|
|
|
// try to stuff obj into an object with an extra slot
|
2010-01-17 17:43:46 +00:00
|
|
|
for(var i=0; Contents(i); ++i)
|
2010-02-02 15:09:56 +00:00
|
|
|
if (Contents(i)->~HasExtraSlot())
|
|
|
|
if (!(Contents(i)->Contents(0)))
|
|
|
|
if (Contents(i)->Collect(obj,true))
|
2010-01-18 01:58:46 +00:00
|
|
|
return true;
|
2010-03-25 20:53:41 +00:00
|
|
|
|
|
|
|
// try to stuff an object in clonk into obj if it has an extra slot
|
|
|
|
if (obj->~HasExtraSlot())
|
|
|
|
if (!(obj->Contents(0)))
|
|
|
|
for(var i=0; Contents(i); ++i)
|
|
|
|
if (obj->Collect(Contents(i),true))
|
|
|
|
return false;
|
|
|
|
|
2010-01-17 17:43:46 +00:00
|
|
|
|
2009-12-29 13:44:16 +00:00
|
|
|
// check max contents
|
|
|
|
if (ContentsCount() >= MaxContentsCount()) return true;
|
2010-03-25 23:56:55 +00:00
|
|
|
|
|
|
|
// check if the two first slots are full. If the overloaded
|
|
|
|
// Collect() is called, this check will be skipped
|
2011-08-11 14:37:46 +00:00
|
|
|
if (!force_collection)
|
2010-03-25 23:56:55 +00:00
|
|
|
if (GetItem(0) && GetItem(1))
|
|
|
|
return true;
|
|
|
|
|
2009-12-29 13:44:16 +00:00
|
|
|
return _inherited(objid,obj,...);
|
|
|
|
}
|
|
|
|
|
2010-11-25 18:03:19 +00:00
|
|
|
public func GetUsedObject() { return using; }
|
|
|
|
|
2009-12-29 13:44:16 +00:00
|
|
|
/* ################################################# */
|
|
|
|
|
|
|
|
// The using-command hast to be canceled if the clonk is entered into
|
|
|
|
// or exited from a building.
|
|
|
|
|
|
|
|
protected func Entrance() { CancelUse(); return _inherited(...); }
|
|
|
|
protected func Departure() { CancelUse(); return _inherited(...); }
|
|
|
|
|
|
|
|
// The same for vehicles
|
|
|
|
protected func AttachTargetLost() { CancelUse(); return _inherited(...); }
|
2010-03-25 23:56:55 +00:00
|
|
|
|
|
|
|
// ...aaand the same for when the clonk is deselected
|
|
|
|
protected func CrewSelection(bool unselect)
|
|
|
|
{
|
2010-09-13 15:27:48 +00:00
|
|
|
if (unselect)
|
2010-04-09 15:06:28 +00:00
|
|
|
{
|
|
|
|
// cancel usage on unselect first...
|
|
|
|
CancelUse();
|
|
|
|
// and if there is still a menu, cancel it too...
|
|
|
|
CancelMenu();
|
|
|
|
}
|
2010-03-25 23:56:55 +00:00
|
|
|
return _inherited(unselect,...);
|
|
|
|
}
|
|
|
|
|
2010-04-09 15:06:28 +00:00
|
|
|
protected func Destruction()
|
|
|
|
{
|
|
|
|
// close open menus, cancel usage...
|
|
|
|
CancelUse();
|
|
|
|
CancelMenu();
|
|
|
|
return _inherited(...);
|
|
|
|
}
|
|
|
|
|
|
|
|
protected func Death()
|
|
|
|
{
|
|
|
|
// close open menus, cancel usage...
|
|
|
|
CancelUse();
|
|
|
|
CancelMenu();
|
|
|
|
return _inherited(...);
|
|
|
|
}
|
|
|
|
|
2010-08-19 11:17:43 +00:00
|
|
|
protected func OnActionChanged(string oldaction)
|
|
|
|
{
|
|
|
|
var old_act = this["ActMap"][oldaction];
|
|
|
|
var act = this["ActMap"][GetAction()];
|
|
|
|
var old_proc = 0;
|
|
|
|
if(old_act) old_proc = old_act["Procedure"];
|
|
|
|
var proc = 0;
|
|
|
|
if(act) proc = act["Procedure"];
|
|
|
|
// if the object's procedure has changed from a non Push/Attach
|
|
|
|
// to a Push/Attach action or the other way round, the usage needs
|
|
|
|
// to be cancelled
|
|
|
|
if (proc != old_proc)
|
|
|
|
{
|
|
|
|
if (proc == DFA_PUSH || proc == DFA_ATTACH
|
|
|
|
|| old_proc == DFA_PUSH || old_proc == DFA_ATTACH)
|
|
|
|
{
|
|
|
|
CancelUse();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return _inherited(oldaction,...);
|
|
|
|
}
|
2010-03-25 23:56:55 +00:00
|
|
|
|
|
|
|
/* +++++++++++++++++++++++++++ Clonk Control +++++++++++++++++++++++++++ */
|
|
|
|
|
2010-10-09 17:08:58 +00:00
|
|
|
local using, using_type;
|
2010-03-25 23:56:55 +00:00
|
|
|
local alt;
|
|
|
|
local mlastx, mlasty;
|
|
|
|
local virtual_cursor;
|
|
|
|
local noholdingcallbacks;
|
2010-12-08 00:56:48 +00:00
|
|
|
local backpack_open;
|
2009-12-29 13:44:16 +00:00
|
|
|
|
|
|
|
/* Main control function */
|
|
|
|
public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool repeat, bool release)
|
|
|
|
{
|
2011-03-06 15:59:58 +00:00
|
|
|
if (!this) return false;
|
2009-12-29 13:44:16 +00:00
|
|
|
|
2010-02-24 23:06:25 +00:00
|
|
|
//Log(Format("%d, %d, %s, strength: %d, repeat: %v, release: %v", x,y,GetPlayerControlName(ctrl), strength, repeat, release),this);
|
2009-12-29 13:44:16 +00:00
|
|
|
|
2010-04-09 15:06:28 +00:00
|
|
|
// open / close backpack
|
2010-03-25 23:56:55 +00:00
|
|
|
if (ctrl == CON_Backpack)
|
|
|
|
{
|
2010-12-08 00:56:48 +00:00
|
|
|
var closed = false;
|
|
|
|
var backpack_was_open = backpack_open;
|
|
|
|
// close if menu was open
|
|
|
|
if(GetMenu())
|
2010-03-25 23:56:55 +00:00
|
|
|
{
|
2010-04-25 01:36:52 +00:00
|
|
|
GetMenu()->Close();
|
2010-12-08 00:56:48 +00:00
|
|
|
closed = true;
|
2010-03-25 23:56:55 +00:00
|
|
|
}
|
2010-12-08 00:56:48 +00:00
|
|
|
// open if no menu was open or it was not the backpack menu which was open
|
|
|
|
if(MaxContentsCount() > 2 && (!closed || !backpack_was_open))
|
2010-03-25 23:56:55 +00:00
|
|
|
{
|
2010-04-29 01:55:44 +00:00
|
|
|
// Cancel usage
|
|
|
|
CancelUse();
|
2010-07-31 13:23:03 +00:00
|
|
|
CreateRingMenu(Icon_Backpack,this);
|
2010-04-09 15:06:28 +00:00
|
|
|
// CreateRingMenu calls SetMenu(this) in the clonk,
|
|
|
|
// so after this call menu = the created menu
|
|
|
|
|
|
|
|
// for all contents in the clonks except the first two (hand slots)
|
2010-03-25 23:56:55 +00:00
|
|
|
for(var i = 2; i < MaxContentsCount(); ++i)
|
|
|
|
{
|
2010-04-09 15:06:28 +00:00
|
|
|
// put them in the menu
|
2010-03-25 23:56:55 +00:00
|
|
|
var item = GetItem(i);
|
2010-04-25 01:36:52 +00:00
|
|
|
GetMenu()->AddItem(item,nil,i);
|
2010-03-25 23:56:55 +00:00
|
|
|
}
|
2010-04-09 15:06:28 +00:00
|
|
|
// finally, show the menu.
|
2010-12-08 00:56:48 +00:00
|
|
|
backpack_open = true;
|
2010-04-25 01:36:52 +00:00
|
|
|
GetMenu()->Show();
|
2010-03-25 23:56:55 +00:00
|
|
|
}
|
2011-03-06 15:59:58 +00:00
|
|
|
return true;
|
2010-03-25 23:56:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* aiming with mouse:
|
|
|
|
The CON_Aim control is transformed into a use command. Con_Use if
|
|
|
|
repeated does not bear the updated x,y coordinates, that's why this
|
|
|
|
other control needs to be issued and transformed. CON_Aim is a
|
|
|
|
control which is issued on mouse move but disabled when not aiming
|
|
|
|
or when HoldingEnabled() of the used item does not return true.
|
|
|
|
For the rest of the control code, it looks like the x,y coordinates
|
|
|
|
came from CON_Use.
|
|
|
|
*/
|
2010-04-25 01:36:52 +00:00
|
|
|
if (using && ctrl == CON_Aim)
|
2009-12-29 13:44:16 +00:00
|
|
|
{
|
2010-02-04 01:08:21 +00:00
|
|
|
if (alt) ctrl = CON_UseAlt;
|
|
|
|
else ctrl = CON_Use;
|
2010-02-02 15:09:56 +00:00
|
|
|
|
2010-02-04 01:08:21 +00:00
|
|
|
repeat = true;
|
|
|
|
release = false;
|
2009-12-29 13:44:16 +00:00
|
|
|
}
|
2010-03-25 23:56:55 +00:00
|
|
|
// controls except a few reset a previously given command
|
2009-12-29 13:44:16 +00:00
|
|
|
else SetCommand("None");
|
|
|
|
|
2010-03-25 23:56:55 +00:00
|
|
|
/* aiming with analog pad or keys:
|
|
|
|
This works completely different. There are CON_AimAxis* and CON_Aim*,
|
|
|
|
both work about the same. A virtual cursor is created which moves in a
|
|
|
|
circle around the clonk and is controlled via these CON_Aim* functions.
|
|
|
|
CON_Aim* is normally on the same buttons as the movement and has a
|
|
|
|
higher priority, thus is called first. The aim is always done, even if
|
|
|
|
the clonk is not aiming. However this returns only true (=handled) if
|
|
|
|
the clonk is really aiming. So if the clonk is not aiming, the virtual
|
|
|
|
cursor aims into the direction in which the clonk is running and e.g.
|
|
|
|
CON_Left is still called afterwards. So if the clonk finally starts to
|
|
|
|
aim, the virtual cursor already aims into the direction in which he ran
|
|
|
|
*/
|
|
|
|
if (ctrl == CON_AimAxisUp || ctrl == CON_AimAxisDown || ctrl == CON_AimAxisLeft || ctrl == CON_AimAxisRight
|
|
|
|
|| ctrl == CON_AimUp || ctrl == CON_AimDown || ctrl == CON_AimLeft || ctrl == CON_AimRight)
|
2010-03-03 18:02:47 +00:00
|
|
|
{
|
|
|
|
var success = VirtualCursor()->Aim(ctrl,this,strength,repeat,release);
|
2010-03-25 23:56:55 +00:00
|
|
|
// in any case, CON_Aim* is called but it is only successful if the virtual cursor is aiming
|
2011-03-06 15:59:58 +00:00
|
|
|
return success && VirtualCursor()->IsAiming();
|
2010-03-03 18:02:47 +00:00
|
|
|
}
|
2010-03-25 23:56:55 +00:00
|
|
|
|
|
|
|
// save last mouse position:
|
|
|
|
// if the using has to be canceled, no information about the current x,y
|
|
|
|
// is available. Thus, the last x,y position needs to be saved
|
2010-02-02 15:09:56 +00:00
|
|
|
if (ctrl == CON_Use || ctrl == CON_UseAlt)
|
|
|
|
{
|
|
|
|
mlastx = x;
|
|
|
|
mlasty = y;
|
|
|
|
}
|
|
|
|
|
2009-12-29 13:44:16 +00:00
|
|
|
// hotkeys (inventory, vehicle and structure control)
|
|
|
|
var hot = 0;
|
|
|
|
if (ctrl == CON_Hotkey0) hot = 10;
|
|
|
|
if (ctrl == CON_Hotkey1) hot = 1;
|
|
|
|
if (ctrl == CON_Hotkey2) hot = 2;
|
|
|
|
if (ctrl == CON_Hotkey3) hot = 3;
|
|
|
|
if (ctrl == CON_Hotkey4) hot = 4;
|
|
|
|
if (ctrl == CON_Hotkey5) hot = 5;
|
|
|
|
if (ctrl == CON_Hotkey6) hot = 6;
|
|
|
|
if (ctrl == CON_Hotkey7) hot = 7;
|
|
|
|
if (ctrl == CON_Hotkey8) hot = 8;
|
|
|
|
if (ctrl == CON_Hotkey9) hot = 9;
|
|
|
|
|
2010-03-22 15:40:54 +00:00
|
|
|
if (hot > 0)
|
|
|
|
{
|
2010-04-25 01:36:52 +00:00
|
|
|
this->~ControlHotkey(hot-1);
|
2011-03-06 15:59:58 +00:00
|
|
|
return true;
|
2010-03-22 15:40:54 +00:00
|
|
|
}
|
2009-12-29 13:44:16 +00:00
|
|
|
|
|
|
|
var proc = GetProcedure();
|
|
|
|
|
2010-02-02 15:09:56 +00:00
|
|
|
// cancel usage
|
|
|
|
if (using && ctrl == CON_CancelUse)
|
|
|
|
{
|
|
|
|
CancelUse();
|
2011-03-06 15:59:58 +00:00
|
|
|
return true;
|
2010-02-02 15:09:56 +00:00
|
|
|
}
|
2010-06-24 19:55:01 +00:00
|
|
|
|
|
|
|
// Push controls
|
|
|
|
if (ctrl == CON_Grab || ctrl == CON_Ungrab || ctrl == CON_PushEnter || ctrl == CON_GrabPrevious || ctrl == CON_GrabNext)
|
2011-03-06 15:59:58 +00:00
|
|
|
return ObjectControlPush(plr, ctrl);
|
2010-06-24 19:55:01 +00:00
|
|
|
|
|
|
|
// Entrance controls
|
|
|
|
if (ctrl == CON_Enter || ctrl == CON_Exit)
|
2011-03-06 15:59:58 +00:00
|
|
|
return ObjectControlEntrance(plr,ctrl);
|
2010-06-24 19:55:01 +00:00
|
|
|
|
|
|
|
// Interact controls
|
|
|
|
if (ctrl == CON_Interact)
|
2011-03-06 15:59:58 +00:00
|
|
|
return ObjectControlInteract(plr,ctrl);
|
2010-06-24 19:55:01 +00:00
|
|
|
|
|
|
|
// building, vehicle, mount, contents, menu control
|
2009-12-29 13:44:16 +00:00
|
|
|
var house = Contained();
|
|
|
|
var vehicle = GetActionTarget();
|
2010-10-07 16:02:52 +00:00
|
|
|
// the clonk can have an action target even though he lost his action.
|
|
|
|
// That's why the clonk may only interact with a vehicle if in an
|
|
|
|
// appropiate procedure:
|
|
|
|
if (proc != "ATTACH" && proc != "PUSH")
|
|
|
|
vehicle = nil;
|
2010-02-02 15:09:56 +00:00
|
|
|
|
2010-09-22 14:49:44 +00:00
|
|
|
// menu
|
2010-03-22 15:40:54 +00:00
|
|
|
if (menu)
|
|
|
|
{
|
2011-03-06 15:59:58 +00:00
|
|
|
return Control2Menu(ctrl, x,y,strength, repeat, release);
|
2010-03-22 15:40:54 +00:00
|
|
|
}
|
2010-09-22 14:49:44 +00:00
|
|
|
|
2011-01-03 20:15:19 +00:00
|
|
|
var contents = GetItem(0);
|
|
|
|
var contents2 = GetItem(1);
|
|
|
|
|
2010-09-22 14:49:44 +00:00
|
|
|
// usage
|
|
|
|
var use = (ctrl == CON_Use || ctrl == CON_UseDelayed || ctrl == CON_UseAlt || ctrl == CON_UseAltDelayed);
|
|
|
|
if (use)
|
2010-02-15 23:33:38 +00:00
|
|
|
{
|
2010-09-22 14:49:44 +00:00
|
|
|
if (house)
|
|
|
|
{
|
2011-03-06 15:59:58 +00:00
|
|
|
return ControlUse2Script(ctrl, x, y, strength, repeat, release, house);
|
2010-09-22 14:49:44 +00:00
|
|
|
}
|
2010-02-15 23:33:38 +00:00
|
|
|
// control to grabbed vehicle
|
2010-09-22 14:49:44 +00:00
|
|
|
else if (vehicle && proc == "PUSH")
|
|
|
|
{
|
2011-03-06 15:59:58 +00:00
|
|
|
return ControlUse2Script(ctrl, x, y, strength, repeat, release, vehicle);
|
2010-09-22 14:49:44 +00:00
|
|
|
}
|
|
|
|
else if (vehicle && proc == "ATTACH")
|
2010-05-28 19:29:32 +00:00
|
|
|
{
|
2010-09-22 14:49:44 +00:00
|
|
|
/* objects to which clonks are attached (like horses, mechs,...) have
|
|
|
|
a special handling:
|
|
|
|
Use controls are, forwarded to the
|
|
|
|
horse but if the control is considered unhandled (return false) on
|
|
|
|
the start of the usage, the control is forwarded further to the
|
|
|
|
item. If the item then returns true on the call, that item is
|
|
|
|
regarded as the used item for the subsequent ControlUse* calls.
|
|
|
|
BUT the horse always gets the ControlUse*-calls that'd go to the used
|
|
|
|
item, too and before it so it can decide at any time to cancel its
|
|
|
|
usage via CancelUse().
|
|
|
|
*/
|
|
|
|
|
2010-10-09 17:08:58 +00:00
|
|
|
if (ControlUse2Script(ctrl, x, y, strength, repeat, release, vehicle))
|
2011-03-06 15:59:58 +00:00
|
|
|
return true;
|
2010-07-17 14:37:44 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
// handled if the horse is the used object
|
|
|
|
// ("using" is set to the object in StartUse(Delayed)Control - when the
|
|
|
|
// object returns true on that callback. Exactly what we want)
|
2011-03-06 15:59:58 +00:00
|
|
|
if (using == vehicle) return true;
|
2010-07-17 14:37:44 +00:00
|
|
|
// has been cancelled (it is not the start of the usage but no object is used)
|
2011-03-06 15:59:58 +00:00
|
|
|
if (!using && (repeat || release)) return true;
|
2010-07-17 14:37:44 +00:00
|
|
|
}
|
2010-05-28 19:29:32 +00:00
|
|
|
}
|
2010-09-22 14:49:44 +00:00
|
|
|
// Release commands are always forwarded even if contents is 0, in case we
|
|
|
|
// need to cancel use of an object that left inventory
|
2011-01-03 20:15:19 +00:00
|
|
|
if ((contents || (release && using)) && (ctrl == CON_Use || ctrl == CON_UseDelayed))
|
2010-09-22 14:49:44 +00:00
|
|
|
{
|
2010-10-09 17:08:58 +00:00
|
|
|
if (ControlUse2Script(ctrl, x, y, strength, repeat, release, contents))
|
2011-03-06 15:59:58 +00:00
|
|
|
return true;
|
2010-09-22 14:49:44 +00:00
|
|
|
}
|
2011-01-03 20:15:19 +00:00
|
|
|
else if ((contents2 || (release && using)) && (ctrl == CON_UseAlt || ctrl == CON_UseAltDelayed))
|
2010-09-22 14:49:44 +00:00
|
|
|
{
|
2010-10-09 17:08:58 +00:00
|
|
|
if (ControlUse2Script(ctrl, x, y, strength, repeat, release, contents2))
|
2011-03-06 15:59:58 +00:00
|
|
|
return true;
|
2010-09-22 14:49:44 +00:00
|
|
|
}
|
2009-12-29 13:44:16 +00:00
|
|
|
}
|
|
|
|
|
2011-08-11 14:37:46 +00:00
|
|
|
// Collecting
|
|
|
|
if (ctrl == CON_Collect)
|
|
|
|
{
|
|
|
|
var dx = -GetDefWidth()/2, dy = -GetDefHeight()/2;
|
|
|
|
var wdt = GetDefWidth(), hgt = GetDefHeight();
|
|
|
|
var obj = FindObject(Find_InRect(dx,dy,wdt,hgt), Find_OCF(OCF_Collectible), Find_NoContainer());
|
|
|
|
if(obj)
|
|
|
|
{
|
|
|
|
// hackery to prevent the clonk from rejecting the collect because it is not being
|
|
|
|
// collected into the hands
|
|
|
|
Collect(obj,nil,nil,true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-09-22 14:49:44 +00:00
|
|
|
// Throwing and dropping
|
2009-12-29 13:44:16 +00:00
|
|
|
// only if not in house, not grabbing a vehicle and an item selected
|
2010-10-07 16:02:52 +00:00
|
|
|
if (!house && (!vehicle || proc == "ATTACH"))
|
2009-12-29 13:44:16 +00:00
|
|
|
{
|
|
|
|
if (contents)
|
|
|
|
{
|
|
|
|
// throw
|
|
|
|
if (ctrl == CON_Throw)
|
|
|
|
{
|
2011-02-13 20:37:58 +00:00
|
|
|
CancelUse();
|
2010-03-30 16:48:38 +00:00
|
|
|
if (proc == "SCALE" || proc == "HANGLE")
|
2011-03-06 15:59:58 +00:00
|
|
|
return ObjectCommand("Drop", contents);
|
2010-03-30 16:48:38 +00:00
|
|
|
else
|
2011-03-06 15:59:58 +00:00
|
|
|
return ObjectCommand("Throw", contents, x, y);
|
2009-12-29 13:44:16 +00:00
|
|
|
}
|
2010-02-02 15:09:56 +00:00
|
|
|
// throw delayed
|
2010-02-04 01:08:21 +00:00
|
|
|
if (ctrl == CON_ThrowDelayed)
|
2010-02-02 15:09:56 +00:00
|
|
|
{
|
2011-02-13 20:37:58 +00:00
|
|
|
CancelUse();
|
2010-03-03 18:02:47 +00:00
|
|
|
if (release)
|
2010-02-04 01:08:21 +00:00
|
|
|
{
|
|
|
|
VirtualCursor()->StopAim();
|
|
|
|
|
|
|
|
if (proc == "SCALE" || proc == "HANGLE")
|
2011-03-06 15:59:58 +00:00
|
|
|
return ObjectCommand("Drop", contents);
|
2010-02-04 01:08:21 +00:00
|
|
|
else
|
2011-03-06 15:59:58 +00:00
|
|
|
return ObjectCommand("Throw", contents, mlastx, mlasty);
|
2010-02-04 01:08:21 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-03-23 20:57:30 +00:00
|
|
|
VirtualCursor()->StartAim(this);
|
2011-03-06 15:59:58 +00:00
|
|
|
return true;
|
2010-02-04 01:08:21 +00:00
|
|
|
}
|
2010-02-02 15:09:56 +00:00
|
|
|
}
|
2009-12-29 13:44:16 +00:00
|
|
|
// drop
|
|
|
|
if (ctrl == CON_Drop)
|
|
|
|
{
|
2011-02-13 20:37:58 +00:00
|
|
|
CancelUse();
|
2011-03-06 15:59:58 +00:00
|
|
|
return ObjectCommand("Drop", contents);
|
2009-12-29 13:44:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// same for contents2 (copypasta)
|
|
|
|
if (contents2)
|
|
|
|
{
|
|
|
|
// throw
|
|
|
|
if (ctrl == CON_ThrowAlt)
|
|
|
|
{
|
2011-02-13 20:37:58 +00:00
|
|
|
CancelUse();
|
2010-09-13 15:27:48 +00:00
|
|
|
if (proc == "SCALE" || proc == "HANGLE")
|
2011-03-06 15:59:58 +00:00
|
|
|
return ObjectCommand("Drop", contents2);
|
2010-09-13 15:27:48 +00:00
|
|
|
else
|
2011-03-06 15:59:58 +00:00
|
|
|
return ObjectCommand("Throw", contents2, x, y);
|
2009-12-29 13:44:16 +00:00
|
|
|
}
|
2010-02-02 15:09:56 +00:00
|
|
|
// throw delayed
|
2010-02-04 01:08:21 +00:00
|
|
|
if (ctrl == CON_ThrowAltDelayed)
|
2010-02-02 15:09:56 +00:00
|
|
|
{
|
2011-02-13 20:37:58 +00:00
|
|
|
CancelUse();
|
2010-03-03 18:02:47 +00:00
|
|
|
if (release)
|
2010-02-04 01:08:21 +00:00
|
|
|
{
|
|
|
|
VirtualCursor()->StopAim();
|
|
|
|
|
|
|
|
if (proc == "SCALE" || proc == "HANGLE")
|
2011-03-06 15:59:58 +00:00
|
|
|
return ObjectCommand("Drop", contents2);
|
2010-02-04 01:08:21 +00:00
|
|
|
else
|
2011-03-06 15:59:58 +00:00
|
|
|
return ObjectCommand("Throw", contents2, mlastx, mlasty);
|
2010-02-04 01:08:21 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-02-13 20:37:58 +00:00
|
|
|
CancelUse();
|
2010-03-23 20:57:30 +00:00
|
|
|
VirtualCursor()->StartAim(this);
|
2011-03-06 15:59:58 +00:00
|
|
|
return true;
|
2010-02-04 01:08:21 +00:00
|
|
|
}
|
2010-02-02 15:09:56 +00:00
|
|
|
}
|
2009-12-29 13:44:16 +00:00
|
|
|
// drop
|
|
|
|
if (ctrl == CON_DropAlt)
|
|
|
|
{
|
2011-03-06 15:59:58 +00:00
|
|
|
return ObjectCommand("Drop", contents2);
|
2009-12-29 13:44:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-06-25 17:06:59 +00:00
|
|
|
// Movement controls (defined in PlayerControl.c, partly overloaded here)
|
|
|
|
if (ctrl == CON_Left || ctrl == CON_Right || ctrl == CON_Up || ctrl == CON_Down || ctrl == CON_Jump)
|
2010-09-22 14:49:44 +00:00
|
|
|
{
|
|
|
|
// forward to script...
|
|
|
|
if (house)
|
|
|
|
{
|
2011-03-06 15:59:58 +00:00
|
|
|
return ControlMovement2Script(ctrl, x, y, strength, repeat, release, house);
|
2010-09-22 14:49:44 +00:00
|
|
|
}
|
|
|
|
else if (vehicle)
|
|
|
|
{
|
2011-03-06 15:59:58 +00:00
|
|
|
if (ControlMovement2Script(ctrl, x, y, strength, repeat, release, vehicle)) return true;
|
2010-09-22 14:49:44 +00:00
|
|
|
}
|
|
|
|
|
2011-03-06 15:59:58 +00:00
|
|
|
return ObjectControlMovement(plr, ctrl, strength, release);
|
2010-09-22 14:49:44 +00:00
|
|
|
}
|
2010-06-25 17:06:59 +00:00
|
|
|
|
2009-12-29 13:44:16 +00:00
|
|
|
// Unhandled control
|
2011-03-06 15:59:58 +00:00
|
|
|
return false;
|
2009-12-29 13:44:16 +00:00
|
|
|
}
|
|
|
|
|
2010-03-03 18:02:47 +00:00
|
|
|
public func ObjectControlMovement(int plr, int ctrl, int strength, bool release)
|
|
|
|
{
|
2010-03-25 23:56:55 +00:00
|
|
|
// from PlayerControl.c
|
|
|
|
var result = inherited(plr,ctrl,strength,release,...);
|
2010-03-03 18:02:47 +00:00
|
|
|
|
2010-03-25 23:56:55 +00:00
|
|
|
// do the following only if strength >= CON_Gamepad_Deadzone
|
2010-03-03 18:02:47 +00:00
|
|
|
if(!release)
|
|
|
|
if(strength != nil && strength < CON_Gamepad_Deadzone)
|
|
|
|
return result;
|
|
|
|
|
2010-03-25 23:56:55 +00:00
|
|
|
|
2010-03-03 18:02:47 +00:00
|
|
|
virtual_cursor = FindObject(Find_ID(GUI_Crosshair),Find_Owner(GetOwner()));
|
|
|
|
if(!virtual_cursor) return result;
|
|
|
|
|
2010-03-25 23:56:55 +00:00
|
|
|
// change direction of virtual_cursor
|
2010-03-03 18:02:47 +00:00
|
|
|
if(!release)
|
|
|
|
virtual_cursor->Direction(ctrl);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2009-12-29 13:44:16 +00:00
|
|
|
public func ObjectCommand(string command, object target, int tx, int ty, object target2)
|
|
|
|
{
|
|
|
|
// special control for throw and jump
|
|
|
|
// but only with controls, not with general commands
|
2010-03-25 23:56:55 +00:00
|
|
|
if (command == "Throw") this->~ControlThrow(target,tx,ty);
|
|
|
|
else if (command == "Jump") this->~ControlJump();
|
2009-12-29 13:44:16 +00:00
|
|
|
// else standard command
|
|
|
|
else SetCommand(command,target,tx,ty,target2);
|
2010-07-31 12:56:15 +00:00
|
|
|
|
|
|
|
// this function might be obsolete: a normal SetCommand does make a callback to
|
|
|
|
// script before it is executed: ControlCommand(szCommand, pTarget, iTx, iTy)
|
2009-12-29 13:44:16 +00:00
|
|
|
}
|
|
|
|
|
2010-03-25 23:56:55 +00:00
|
|
|
/* ++++++++++++++++++++++++ Use Controls ++++++++++++++++++++++++ */
|
|
|
|
|
2010-02-04 15:44:01 +00:00
|
|
|
public func CancelUse()
|
2009-12-29 13:44:16 +00:00
|
|
|
{
|
|
|
|
if (!using) return;
|
2010-06-25 17:20:50 +00:00
|
|
|
|
2010-03-25 23:56:55 +00:00
|
|
|
// use the saved x,y coordinates for canceling
|
2010-10-09 17:08:58 +00:00
|
|
|
CancelUseControl(mlastx, mlasty);
|
2009-12-29 13:44:16 +00:00
|
|
|
}
|
|
|
|
|
2010-07-17 14:37:44 +00:00
|
|
|
// for testing if the calls in ControlUse2Script are issued correctly
|
2010-05-28 19:29:32 +00:00
|
|
|
//global func Call(string call)
|
|
|
|
//{
|
|
|
|
// Log("calling %s to %s",call,GetName());
|
|
|
|
// return inherited(call,...);
|
|
|
|
//}
|
|
|
|
|
2010-10-09 17:08:58 +00:00
|
|
|
private func DetermineUsageType(object obj)
|
|
|
|
{
|
|
|
|
// house
|
|
|
|
if (obj == Contained())
|
|
|
|
return C4D_Structure;
|
|
|
|
// object
|
|
|
|
if (obj)
|
|
|
|
if (obj->Contained() == this)
|
|
|
|
return C4D_Object;
|
|
|
|
// vehicle
|
|
|
|
var proc = GetProcedure();
|
|
|
|
if (obj == GetActionTarget())
|
|
|
|
if (proc == "ATTACH" && proc == "PUSH")
|
|
|
|
return C4D_Vehicle;
|
|
|
|
// unkown
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
private func GetUseCallString(string action) {
|
|
|
|
// Control... or Contained...
|
|
|
|
var control = "Control";
|
|
|
|
if (using_type == C4D_Structure) control = "Contained";
|
|
|
|
// ..Use.. or ..UseAlt...
|
|
|
|
var estr = "";
|
|
|
|
if (alt && using_type != C4D_Object) estr = "Alt";
|
|
|
|
// Action
|
|
|
|
if (!action) action = "";
|
|
|
|
|
|
|
|
return Format("~%sUse%s%s",control,estr,action);
|
|
|
|
}
|
|
|
|
|
|
|
|
private func StartUseControl(int ctrl, int x, int y, object obj)
|
2009-12-29 13:44:16 +00:00
|
|
|
{
|
2010-01-22 16:29:46 +00:00
|
|
|
using = obj;
|
2010-10-09 17:08:58 +00:00
|
|
|
using_type = DetermineUsageType(obj);
|
|
|
|
alt = ctrl != CON_Use;
|
|
|
|
|
2010-01-22 16:29:46 +00:00
|
|
|
var hold_enabled = obj->Call("~HoldingEnabled");
|
|
|
|
|
2010-02-02 15:09:56 +00:00
|
|
|
if (hold_enabled)
|
2010-01-22 16:29:46 +00:00
|
|
|
SetPlayerControlEnabled(GetOwner(), CON_Aim, true);
|
2010-10-09 17:08:58 +00:00
|
|
|
|
2010-01-22 16:29:46 +00:00
|
|
|
// first call UseStart. If unhandled, call Use (mousecontrol)
|
2010-10-09 17:08:58 +00:00
|
|
|
var handled = obj->Call(GetUseCallString("Start"),this,x,y);
|
2010-01-22 16:29:46 +00:00
|
|
|
if (!handled)
|
2010-02-04 15:44:01 +00:00
|
|
|
{
|
2010-10-09 17:08:58 +00:00
|
|
|
handled = obj->Call(GetUseCallString(),this,x,y);
|
2010-02-04 15:44:01 +00:00
|
|
|
noholdingcallbacks = handled;
|
|
|
|
}
|
2010-01-22 16:29:46 +00:00
|
|
|
if (!handled)
|
|
|
|
{
|
|
|
|
using = nil;
|
2010-10-09 17:08:58 +00:00
|
|
|
using_type = nil;
|
2010-02-02 15:09:56 +00:00
|
|
|
if (hold_enabled)
|
2010-01-22 16:29:46 +00:00
|
|
|
SetPlayerControlEnabled(GetOwner(), CON_Aim, false);
|
|
|
|
return false;
|
|
|
|
}
|
2009-12-29 13:44:16 +00:00
|
|
|
|
|
|
|
return handled;
|
|
|
|
}
|
|
|
|
|
2010-10-09 17:08:58 +00:00
|
|
|
private func StartUseDelayedControl(int ctrl, object obj)
|
2010-02-02 15:09:56 +00:00
|
|
|
{
|
|
|
|
using = obj;
|
2010-10-09 17:08:58 +00:00
|
|
|
using_type = DetermineUsageType(obj);
|
|
|
|
alt = ctrl != CON_UseDelayed;
|
2010-02-02 15:09:56 +00:00
|
|
|
|
2010-03-23 20:57:30 +00:00
|
|
|
VirtualCursor()->StartAim(this);
|
2010-02-04 01:08:21 +00:00
|
|
|
|
2010-02-02 15:09:56 +00:00
|
|
|
// call UseStart
|
2010-10-09 17:08:58 +00:00
|
|
|
var handled = obj->Call(GetUseCallString("Start"),this,mlastx,mlasty);
|
|
|
|
noholdingcallbacks = !handled;
|
2010-02-04 01:08:21 +00:00
|
|
|
|
2010-02-02 15:09:56 +00:00
|
|
|
return handled;
|
|
|
|
}
|
|
|
|
|
2010-10-09 17:08:58 +00:00
|
|
|
private func CancelUseControl(int x, int y)
|
2010-01-22 16:29:46 +00:00
|
|
|
{
|
2010-05-28 19:29:32 +00:00
|
|
|
// to horse first (if there is one)
|
|
|
|
var horse = GetActionTarget();
|
|
|
|
if(horse && GetProcedure() == "ATTACH" && using != horse)
|
2010-10-09 17:08:58 +00:00
|
|
|
StopUseControl(x, y, horse, true);
|
2010-05-28 19:29:32 +00:00
|
|
|
|
2010-10-09 17:08:58 +00:00
|
|
|
return StopUseControl(x, y, using, true);
|
2010-01-22 16:29:46 +00:00
|
|
|
}
|
|
|
|
|
2010-10-09 17:08:58 +00:00
|
|
|
private func StopUseControl(int x, int y, object obj, bool cancel)
|
2009-12-29 13:44:16 +00:00
|
|
|
{
|
2010-01-22 16:29:46 +00:00
|
|
|
var stop = "Stop";
|
2010-02-02 15:09:56 +00:00
|
|
|
if (cancel) stop = "Cancel";
|
2010-01-22 16:29:46 +00:00
|
|
|
|
|
|
|
// ControlUseStop, ControlUseAltStop, ContainedUseAltStop, ContainedUseCancel, etc...
|
2010-10-09 17:08:58 +00:00
|
|
|
var handled = obj->Call(GetUseCallString(stop),this,x,y);
|
2010-05-28 19:29:32 +00:00
|
|
|
if (obj == using)
|
|
|
|
{
|
2011-02-13 20:49:02 +00:00
|
|
|
// if ControlUseStop returned -1, the current object is kept as "used object"
|
|
|
|
// but no more callbacks except for ControlUseCancel are made. The usage of this
|
|
|
|
// object is finally cancelled on ControlUseCancel.
|
|
|
|
if(cancel || handled != -1)
|
|
|
|
{
|
|
|
|
using = nil;
|
|
|
|
using_type = nil;
|
|
|
|
alt = false;
|
|
|
|
}
|
2010-05-28 19:29:32 +00:00
|
|
|
noholdingcallbacks = false;
|
|
|
|
|
|
|
|
SetPlayerControlEnabled(GetOwner(), CON_Aim, false);
|
2010-02-24 22:53:17 +00:00
|
|
|
|
2010-05-28 19:29:32 +00:00
|
|
|
if (virtual_cursor)
|
|
|
|
virtual_cursor->StopAim();
|
|
|
|
}
|
2010-02-02 15:09:56 +00:00
|
|
|
|
|
|
|
return handled;
|
|
|
|
}
|
|
|
|
|
2010-10-09 17:08:58 +00:00
|
|
|
private func HoldingUseControl(int ctrl, int x, int y, object obj)
|
2010-02-04 01:08:21 +00:00
|
|
|
{
|
|
|
|
var mex = x;
|
|
|
|
var mey = y;
|
|
|
|
if (ctrl == CON_UseDelayed || ctrl == CON_UseAltDelayed)
|
|
|
|
{
|
|
|
|
mex = mlastx;
|
|
|
|
mey = mlasty;
|
|
|
|
}
|
|
|
|
|
2010-02-04 15:44:01 +00:00
|
|
|
//Message("%d,%d",this,mex,mey);
|
2010-02-25 11:47:13 +00:00
|
|
|
|
2010-03-23 20:57:30 +00:00
|
|
|
// automatic adjustment of the direction
|
2010-02-25 11:47:13 +00:00
|
|
|
// --------------------
|
|
|
|
// if this is desired for ALL objects is the question, we will find out.
|
|
|
|
// For now, this is done for items and vehicles, not for buildings and
|
|
|
|
// mounts (naturally). If turning vehicles just liket hat without issuing
|
|
|
|
// a turning animation is the question. But after all, the clonk can turn
|
|
|
|
// by setting the dir too.
|
|
|
|
|
|
|
|
|
2010-03-08 21:10:55 +00:00
|
|
|
// not riding and not in building not while scaling
|
|
|
|
if (GetProcedure() != "ATTACH" && !Contained() && GetProcedure() != "SCALE")
|
2010-02-25 11:47:13 +00:00
|
|
|
{
|
|
|
|
// pushing vehicle: object to turn is the vehicle
|
|
|
|
var dir_obj = GetActionTarget();
|
2010-10-07 16:02:52 +00:00
|
|
|
if (GetProcedure() != "PUSH") dir_obj = nil;
|
2010-02-25 11:47:13 +00:00
|
|
|
|
|
|
|
// otherwise, turn the clonk
|
2010-03-03 18:02:47 +00:00
|
|
|
if (!dir_obj) dir_obj = this;
|
2010-02-25 11:47:13 +00:00
|
|
|
|
|
|
|
if ((dir_obj->GetComDir() == COMD_Stop && dir_obj->GetXDir() == 0) || dir_obj->GetProcedure() == "FLIGHT")
|
|
|
|
{
|
|
|
|
if (dir_obj->GetDir() == DIR_Left)
|
|
|
|
{
|
|
|
|
if (mex > 0)
|
|
|
|
dir_obj->SetDir(DIR_Right);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (mex < 0)
|
|
|
|
dir_obj->SetDir(DIR_Left);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-02-04 01:08:21 +00:00
|
|
|
|
2010-10-09 17:08:58 +00:00
|
|
|
var handled = obj->Call(GetUseCallString("Holding"),this,mex,mey);
|
2010-02-04 01:08:21 +00:00
|
|
|
|
|
|
|
return handled;
|
|
|
|
}
|
|
|
|
|
2010-10-09 17:08:58 +00:00
|
|
|
private func StopUseDelayedControl(object obj)
|
2010-02-02 15:09:56 +00:00
|
|
|
{
|
|
|
|
// ControlUseStop, ControlUseAltStop, ContainedUseAltStop, etc...
|
2010-10-09 17:08:58 +00:00
|
|
|
|
|
|
|
var handled = obj->Call(GetUseCallString("Stop"),this,mlastx,mlasty);
|
2010-02-02 15:09:56 +00:00
|
|
|
if (!handled)
|
2010-10-09 17:08:58 +00:00
|
|
|
handled = obj->Call(GetUseCallString(),this,mlastx,mlasty);
|
2010-02-04 01:08:21 +00:00
|
|
|
|
2010-05-28 19:29:32 +00:00
|
|
|
if (obj == using)
|
|
|
|
{
|
|
|
|
VirtualCursor()->StopAim();
|
2011-02-13 20:49:02 +00:00
|
|
|
// see StopUseControl
|
|
|
|
if(handled != -1)
|
|
|
|
{
|
|
|
|
using = nil;
|
|
|
|
using_type = nil;
|
|
|
|
alt = false;
|
|
|
|
}
|
2010-05-28 19:29:32 +00:00
|
|
|
noholdingcallbacks = false;
|
|
|
|
}
|
2009-12-29 13:44:16 +00:00
|
|
|
|
|
|
|
return handled;
|
|
|
|
}
|
|
|
|
|
2010-03-25 23:56:55 +00:00
|
|
|
/* Control to menu */
|
|
|
|
|
2010-03-22 15:40:54 +00:00
|
|
|
private func Control2Menu(int ctrl, int x, int y, int strength, bool repeat, bool release)
|
|
|
|
{
|
2010-03-25 23:56:55 +00:00
|
|
|
|
2010-04-25 01:36:52 +00:00
|
|
|
/* all this stuff is already done on a higher layer - in playercontrol.c
|
|
|
|
now this is just the same for gamepad control */
|
2010-09-13 15:27:48 +00:00
|
|
|
|
2010-04-25 01:36:52 +00:00
|
|
|
if (!PlayerHasVirtualCursor(GetOwner()))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
|
|
// fix pos of x and y
|
|
|
|
var mex = mlastx+GetX()-GetMenu()->GetX();
|
|
|
|
var mey = mlasty+GetY()-GetMenu()->GetY();
|
2010-03-25 23:56:55 +00:00
|
|
|
|
|
|
|
// update angle for visual effect on the menu
|
2010-03-23 20:57:30 +00:00
|
|
|
if (repeat)
|
2010-09-13 15:27:48 +00:00
|
|
|
{
|
2010-04-25 01:36:52 +00:00
|
|
|
if (ctrl == CON_UseDelayed || ctrl == CON_UseAltDelayed)
|
|
|
|
this->GetMenu()->~UpdateCursor(mex,mey);
|
2010-03-23 20:57:30 +00:00
|
|
|
}
|
2010-03-25 23:56:55 +00:00
|
|
|
// click on menu
|
2010-03-23 20:57:30 +00:00
|
|
|
if (release)
|
|
|
|
{
|
|
|
|
// select
|
2010-04-25 01:36:52 +00:00
|
|
|
if (ctrl == CON_UseDelayed || ctrl == CON_UseAltDelayed)
|
|
|
|
this->GetMenu()->Select(mex,mey, ctrl == CON_UseAltDelayed);
|
2010-03-23 20:57:30 +00:00
|
|
|
}
|
|
|
|
|
2010-03-22 15:40:54 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-07-17 14:37:44 +00:00
|
|
|
// Control use redirected to script
|
2010-10-09 17:08:58 +00:00
|
|
|
private func ControlUse2Script(int ctrl, int x, int y, int strength, bool repeat, bool release, object obj)
|
2010-09-13 15:27:48 +00:00
|
|
|
{
|
2010-01-22 16:29:46 +00:00
|
|
|
// click on secondary cancels primary and the other way round
|
2009-12-29 13:44:16 +00:00
|
|
|
if (using)
|
|
|
|
{
|
2010-02-24 22:53:17 +00:00
|
|
|
if (ctrl == CON_Use && alt || ctrl == CON_UseAlt && !alt
|
|
|
|
|| ctrl == CON_UseDelayed && alt || ctrl == CON_UseAltDelayed && !alt)
|
2010-01-22 16:29:46 +00:00
|
|
|
{
|
2010-10-09 17:08:58 +00:00
|
|
|
CancelUseControl(x, y);
|
2010-01-22 16:29:46 +00:00
|
|
|
return true;
|
|
|
|
}
|
2009-12-29 13:44:16 +00:00
|
|
|
}
|
2010-02-02 15:09:56 +00:00
|
|
|
|
|
|
|
// standard use
|
2009-12-29 13:44:16 +00:00
|
|
|
if (ctrl == CON_Use || ctrl == CON_UseAlt)
|
|
|
|
{
|
|
|
|
if (!release && !repeat)
|
|
|
|
{
|
2010-10-09 17:08:58 +00:00
|
|
|
return StartUseControl(ctrl,x, y, obj);
|
2009-12-29 13:44:16 +00:00
|
|
|
}
|
2010-10-09 13:30:56 +00:00
|
|
|
else if (release && obj == using)
|
2009-12-29 13:44:16 +00:00
|
|
|
{
|
2010-10-09 17:08:58 +00:00
|
|
|
return StopUseControl(x, y, obj);
|
2009-12-29 13:44:16 +00:00
|
|
|
}
|
2010-02-02 15:09:56 +00:00
|
|
|
}
|
|
|
|
// gamepad use
|
|
|
|
else if (ctrl == CON_UseDelayed || ctrl == CON_UseAltDelayed)
|
|
|
|
{
|
|
|
|
if (!release && !repeat)
|
|
|
|
{
|
2010-10-09 17:08:58 +00:00
|
|
|
return StartUseDelayedControl(ctrl, obj);
|
2010-02-02 15:09:56 +00:00
|
|
|
}
|
2010-10-09 13:30:56 +00:00
|
|
|
else if (release && obj == using)
|
2010-02-02 15:09:56 +00:00
|
|
|
{
|
2010-10-09 17:08:58 +00:00
|
|
|
return StopUseDelayedControl(obj);
|
2010-02-02 15:09:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// more use (holding)
|
|
|
|
if (ctrl == CON_Use || ctrl == CON_UseAlt || ctrl == CON_UseDelayed || ctrl == CON_UseAltDelayed)
|
|
|
|
{
|
2010-03-22 18:33:24 +00:00
|
|
|
if (release)
|
2010-01-03 22:16:35 +00:00
|
|
|
{
|
2010-03-25 23:56:55 +00:00
|
|
|
// leftover use release
|
|
|
|
CancelUse();
|
|
|
|
return true;
|
2010-01-03 22:16:35 +00:00
|
|
|
}
|
2010-03-22 18:33:24 +00:00
|
|
|
else if (repeat && !noholdingcallbacks)
|
2009-12-29 13:44:16 +00:00
|
|
|
{
|
2010-10-09 17:08:58 +00:00
|
|
|
return HoldingUseControl(ctrl, x, y, obj);
|
2009-12-29 13:44:16 +00:00
|
|
|
}
|
|
|
|
}
|
2010-07-17 14:37:44 +00:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Control use redirected to script
|
2010-10-09 17:08:58 +00:00
|
|
|
private func ControlMovement2Script(int ctrl, int x, int y, int strength, bool repeat, bool release, object obj)
|
2010-07-17 14:37:44 +00:00
|
|
|
{
|
2009-12-29 13:44:16 +00:00
|
|
|
// overloads of movement commandos
|
2010-07-17 14:37:44 +00:00
|
|
|
if (ctrl == CON_Left || ctrl == CON_Right || ctrl == CON_Down || ctrl == CON_Up || ctrl == CON_Jump)
|
2009-12-29 13:44:16 +00:00
|
|
|
{
|
2010-10-09 17:08:58 +00:00
|
|
|
var control = "Control";
|
|
|
|
if (Contained() == obj) control = "Contained";
|
|
|
|
|
2009-12-29 13:44:16 +00:00
|
|
|
if (release)
|
|
|
|
{
|
|
|
|
// if any movement key has been released, ControlStop is called
|
2010-02-22 17:48:12 +00:00
|
|
|
if (obj->Call(Format("~%sStop",control),this,ctrl)) return true;
|
2009-12-29 13:44:16 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-02-24 22:53:17 +00:00
|
|
|
// what about deadzone?
|
|
|
|
if (strength != nil && strength < CON_Gamepad_Deadzone)
|
|
|
|
return true;
|
|
|
|
|
2009-12-29 13:44:16 +00:00
|
|
|
// Control*
|
|
|
|
if (ctrl == CON_Left) if (obj->Call(Format("~%sLeft",control),this)) return true;
|
|
|
|
if (ctrl == CON_Right) if (obj->Call(Format("~%sRight",control),this)) return true;
|
|
|
|
if (ctrl == CON_Up) if (obj->Call(Format("~%sUp",control),this)) return true;
|
|
|
|
if (ctrl == CON_Down) if (obj->Call(Format("~%sDown",control),this)) return true;
|
2010-02-23 11:50:14 +00:00
|
|
|
|
|
|
|
// for attached (e.g. horse: also Jump command
|
2010-03-03 18:02:47 +00:00
|
|
|
if (GetProcedure() == "ATTACH")
|
|
|
|
if (ctrl == CON_Jump) if (obj->Call("ControlJump",this)) return true;
|
2009-12-29 13:44:16 +00:00
|
|
|
}
|
|
|
|
}
|
2010-07-17 14:37:44 +00:00
|
|
|
|
2009-12-29 13:44:16 +00:00
|
|
|
}
|
|
|
|
|
2010-03-25 23:56:55 +00:00
|
|
|
// returns true if the clonk is able to enter a building (procedurewise)
|
2009-12-29 13:44:16 +00:00
|
|
|
public func CanEnter()
|
|
|
|
{
|
|
|
|
var proc = GetProcedure();
|
|
|
|
if (proc != "WALK" && proc != "SWIM" && proc != "SCALE" &&
|
|
|
|
proc != "HANGLE" && proc != "FLOAT" && proc != "FLIGHT" &&
|
|
|
|
proc != "PUSH") return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Handles enter and exit
|
|
|
|
private func ObjectControlEntrance(int plr, int ctrl)
|
|
|
|
{
|
|
|
|
var proc = GetProcedure();
|
|
|
|
|
|
|
|
// enter
|
|
|
|
if (ctrl == CON_Enter)
|
|
|
|
{
|
|
|
|
// contained
|
2011-03-06 15:59:58 +00:00
|
|
|
if (Contained()) return false;
|
2009-12-29 13:44:16 +00:00
|
|
|
// enter only if... one can
|
2011-03-06 15:59:58 +00:00
|
|
|
if (!CanEnter()) return false;
|
2009-12-29 13:44:16 +00:00
|
|
|
|
|
|
|
// a building with an entrance at right position is there?
|
|
|
|
var obj = GetEntranceObject();
|
2011-03-06 15:59:58 +00:00
|
|
|
if (!obj) return false;
|
2009-12-29 13:44:16 +00:00
|
|
|
|
2010-07-31 12:56:15 +00:00
|
|
|
ObjectCommand("Enter", obj);
|
2011-03-06 15:59:58 +00:00
|
|
|
return true;
|
2009-12-29 13:44:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// exit
|
|
|
|
if (ctrl == CON_Exit)
|
|
|
|
{
|
2011-03-06 15:59:58 +00:00
|
|
|
if (!Contained()) return false;
|
2009-12-29 13:44:16 +00:00
|
|
|
|
2010-07-31 12:56:15 +00:00
|
|
|
ObjectCommand("Exit");
|
2011-03-06 15:59:58 +00:00
|
|
|
return true;
|
2009-12-29 13:44:16 +00:00
|
|
|
}
|
|
|
|
|
2011-03-06 15:59:58 +00:00
|
|
|
return false;
|
2009-12-29 13:44:16 +00:00
|
|
|
}
|
|
|
|
|
2010-06-24 19:55:01 +00:00
|
|
|
private func ObjectControlInteract(int plr, int ctrl)
|
|
|
|
{
|
2011-10-26 21:03:12 +00:00
|
|
|
var interactables = FindObjects(Find_Or(Find_Container(this), Find_AtPoint(0,0)),
|
|
|
|
Find_Func("IsInteractable",this), Find_Layer(GetObjectLayer()));
|
2010-06-24 19:55:01 +00:00
|
|
|
// if there are several interactable objects, just call the first that returns true
|
|
|
|
for (var interactable in interactables)
|
|
|
|
if (interactable->~Interact(this))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2009-12-29 13:44:16 +00:00
|
|
|
// Handles push controls
|
|
|
|
private func ObjectControlPush(int plr, int ctrl)
|
|
|
|
{
|
2011-03-06 15:59:58 +00:00
|
|
|
if (!this) return false;
|
2009-12-29 13:44:16 +00:00
|
|
|
|
|
|
|
var proc = GetProcedure();
|
|
|
|
|
|
|
|
// grabbing
|
|
|
|
if (ctrl == CON_Grab)
|
|
|
|
{
|
|
|
|
// grab only if he walks
|
2011-03-06 15:59:58 +00:00
|
|
|
if (proc != "WALK") return false;
|
2009-12-29 13:44:16 +00:00
|
|
|
|
|
|
|
// only if there is someting to grab
|
2010-09-20 22:53:16 +00:00
|
|
|
var obj = FindObject(Find_OCF(OCF_Grab), Find_AtPoint(0,0), Find_Exclude(this), Find_Layer(GetObjectLayer()));
|
2011-03-06 15:59:58 +00:00
|
|
|
if (!obj) return false;
|
2009-12-29 13:44:16 +00:00
|
|
|
|
|
|
|
// grab
|
2010-07-31 12:56:15 +00:00
|
|
|
ObjectCommand("Grab", obj);
|
2011-03-06 15:59:58 +00:00
|
|
|
return true;
|
2009-12-29 13:44:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// grab next/previous
|
|
|
|
if (ctrl == CON_GrabNext)
|
2011-03-06 15:59:58 +00:00
|
|
|
return ShiftVehicle(plr, false);
|
2009-12-29 13:44:16 +00:00
|
|
|
if (ctrl == CON_GrabPrevious)
|
2011-03-06 15:59:58 +00:00
|
|
|
return ShiftVehicle(plr, true);
|
2009-12-29 13:44:16 +00:00
|
|
|
|
|
|
|
// ungrabbing
|
|
|
|
if (ctrl == CON_Ungrab)
|
|
|
|
{
|
|
|
|
// ungrab only if he pushes
|
2011-03-06 15:59:58 +00:00
|
|
|
if (proc != "PUSH") return false;
|
2009-12-29 13:44:16 +00:00
|
|
|
|
2010-07-31 12:56:15 +00:00
|
|
|
ObjectCommand("UnGrab");
|
2011-03-06 15:59:58 +00:00
|
|
|
return true;
|
2009-12-29 13:44:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// push into building
|
|
|
|
if (ctrl == CON_PushEnter)
|
|
|
|
{
|
2011-03-06 15:59:58 +00:00
|
|
|
if (proc != "PUSH") return false;
|
2009-12-29 13:44:16 +00:00
|
|
|
|
|
|
|
// respect no push enter
|
2011-03-06 15:59:58 +00:00
|
|
|
if (GetActionTarget()->GetDefCoreVal("NoPushEnter","DefCore")) return false;
|
2009-12-29 13:44:16 +00:00
|
|
|
|
|
|
|
// a building with an entrance at right position is there?
|
|
|
|
var obj = GetActionTarget()->GetEntranceObject();
|
2011-03-06 15:59:58 +00:00
|
|
|
if (!obj) return false;
|
2009-12-29 13:44:16 +00:00
|
|
|
|
2010-07-31 12:56:15 +00:00
|
|
|
ObjectCommand("PushTo", GetActionTarget(), 0, 0, obj);
|
2011-03-06 15:59:58 +00:00
|
|
|
return true;
|
2009-12-29 13:44:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// grabs the next/previous vehicle (if there is any)
|
|
|
|
private func ShiftVehicle(int plr, bool back)
|
|
|
|
{
|
|
|
|
if (!this) return false;
|
|
|
|
|
|
|
|
if (GetProcedure() != "PUSH") return false;
|
|
|
|
|
|
|
|
var lorry = GetActionTarget();
|
|
|
|
// get all grabbable objects
|
2010-09-20 22:53:16 +00:00
|
|
|
var objs = FindObjects(Find_OCF(OCF_Grab), Find_AtPoint(0,0), Find_Exclude(this), Find_Layer(GetObjectLayer()));
|
2009-12-29 13:44:16 +00:00
|
|
|
|
|
|
|
// nothing to switch to (there is no other grabbable object)
|
|
|
|
if (GetLength(objs) <= 1) return false;
|
|
|
|
|
|
|
|
// find out at what index of the array objs the vehicle is located
|
|
|
|
var index = 0;
|
|
|
|
for(var obj in objs)
|
|
|
|
{
|
|
|
|
if (obj == lorry) break;
|
|
|
|
index++;
|
|
|
|
}
|
|
|
|
|
|
|
|
// get the next/previous vehicle
|
|
|
|
if (back)
|
|
|
|
{
|
|
|
|
--index;
|
|
|
|
if (index < 0) index = GetLength(objs)-1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
++index;
|
|
|
|
if (index >= GetLength(objs)) index = 0;
|
|
|
|
}
|
|
|
|
|
2010-07-31 12:56:15 +00:00
|
|
|
ObjectCommand("Grab", objs[index]);
|
2009-12-29 13:44:16 +00:00
|
|
|
|
|
|
|
return true;
|
2010-09-13 15:27:48 +00:00
|
|
|
}
|
2009-12-29 13:44:16 +00:00
|
|
|
|
2010-03-25 23:56:55 +00:00
|
|
|
/* Virtual cursor stuff */
|
|
|
|
|
|
|
|
// get virtual cursor, if noone is there, create it
|
2010-02-02 15:09:56 +00:00
|
|
|
private func VirtualCursor()
|
|
|
|
{
|
2010-03-03 18:02:47 +00:00
|
|
|
if (!virtual_cursor)
|
2010-02-02 15:09:56 +00:00
|
|
|
{
|
2010-03-02 16:24:51 +00:00
|
|
|
virtual_cursor = FindObject(Find_ID(GUI_Crosshair),Find_Owner(GetOwner()));
|
2010-02-04 01:08:21 +00:00
|
|
|
}
|
2010-03-03 18:02:47 +00:00
|
|
|
if (!virtual_cursor)
|
2010-02-04 01:08:21 +00:00
|
|
|
{
|
2010-04-25 01:36:52 +00:00
|
|
|
virtual_cursor = CreateObject(GUI_Crosshair,0,0,GetOwner());
|
2010-02-02 15:09:56 +00:00
|
|
|
}
|
2010-02-04 01:08:21 +00:00
|
|
|
|
2010-02-02 15:09:56 +00:00
|
|
|
return virtual_cursor;
|
|
|
|
}
|
|
|
|
|
2010-03-25 23:56:55 +00:00
|
|
|
// virtual cursor is visible
|
2010-02-04 01:08:21 +00:00
|
|
|
private func VirtualCursorAiming()
|
|
|
|
{
|
2010-03-03 18:02:47 +00:00
|
|
|
if (!virtual_cursor) return false;
|
2010-02-04 01:08:21 +00:00
|
|
|
return virtual_cursor->IsAiming();
|
|
|
|
}
|
|
|
|
|
2010-03-25 23:56:55 +00:00
|
|
|
// store pos of virtual cursor into mlastx, mlasty
|
2010-02-04 01:08:21 +00:00
|
|
|
public func UpdateVirtualCursorPos()
|
|
|
|
{
|
|
|
|
mlastx = VirtualCursor()->GetX()-GetX();
|
|
|
|
mlasty = VirtualCursor()->GetY()-GetY();
|
|
|
|
}
|
|
|
|
|
|
|
|
public func TriggerHoldingControl()
|
|
|
|
{
|
2010-03-23 20:57:30 +00:00
|
|
|
// using has been commented because it must be possible to use the virtual
|
|
|
|
// cursor aim also without a used object - for menus
|
|
|
|
// However, I think the check for 'using' here is just an unecessary safeguard
|
|
|
|
// since there is always a using-object if the clonk is aiming for a throw
|
|
|
|
// or a use. If the clonk uses it, there will be callbacks that cancel the
|
|
|
|
// callbacks to the virtual cursor
|
|
|
|
// - Newton
|
|
|
|
if (/*using && */!noholdingcallbacks)
|
2010-02-04 01:08:21 +00:00
|
|
|
{
|
|
|
|
var ctrl;
|
|
|
|
if (alt) ctrl = CON_UseAltDelayed;
|
|
|
|
else ctrl = CON_UseDelayed;
|
|
|
|
|
|
|
|
ObjectControl(GetOwner(), ctrl, 0, 0, 0, true, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2010-06-25 17:06:59 +00:00
|
|
|
public func IsMounted() { return GetProcedure() == "ATTACH"; }
|
|
|
|
|
2010-03-25 23:56:55 +00:00
|
|
|
/* +++++++++++++++++++++++ Menu control +++++++++++++++++++++++ */
|
2010-03-23 20:57:30 +00:00
|
|
|
|
2010-03-26 15:18:08 +00:00
|
|
|
local menu;
|
|
|
|
|
2010-03-23 20:57:30 +00:00
|
|
|
func HasMenuControl()
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
func SetMenu(object m)
|
|
|
|
{
|
2010-05-07 22:10:09 +00:00
|
|
|
// already the same
|
|
|
|
if (menu == m)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2010-04-25 01:36:52 +00:00
|
|
|
// multiple menus are not supported
|
2010-03-23 20:57:30 +00:00
|
|
|
if (menu && m)
|
|
|
|
{
|
|
|
|
menu->Close();
|
|
|
|
}
|
|
|
|
// new one
|
|
|
|
menu = m;
|
|
|
|
if (menu)
|
2010-09-13 15:27:48 +00:00
|
|
|
{
|
2010-06-25 17:20:50 +00:00
|
|
|
CancelUse();
|
2010-03-26 14:43:17 +00:00
|
|
|
// stop clonk
|
|
|
|
SetComDir(COMD_Stop);
|
|
|
|
|
2010-03-23 20:57:30 +00:00
|
|
|
if (PlayerHasVirtualCursor(GetOwner()))
|
2010-04-25 01:36:52 +00:00
|
|
|
VirtualCursor()->StartAim(this,false,menu);
|
2010-03-23 20:57:30 +00:00
|
|
|
else
|
2010-04-25 01:36:52 +00:00
|
|
|
{
|
2011-11-20 21:09:53 +00:00
|
|
|
if (menu->~CursorUpdatesEnabled()) {
|
|
|
|
SetPlayerControlEnabled(GetOwner(), CON_GUICursor, true);
|
|
|
|
}
|
2010-04-25 01:36:52 +00:00
|
|
|
SetPlayerControlEnabled(GetOwner(), CON_GUIClick1, true);
|
|
|
|
SetPlayerControlEnabled(GetOwner(), CON_GUIClick2, true);
|
|
|
|
}
|
2010-03-23 20:57:30 +00:00
|
|
|
}
|
|
|
|
// close menu
|
|
|
|
if (!menu)
|
|
|
|
{
|
2010-05-07 22:10:09 +00:00
|
|
|
if (virtual_cursor)
|
|
|
|
virtual_cursor->StopAim();
|
2010-04-25 01:36:52 +00:00
|
|
|
|
|
|
|
SetPlayerControlEnabled(GetOwner(), CON_GUICursor, false);
|
|
|
|
SetPlayerControlEnabled(GetOwner(), CON_GUIClick1, false);
|
|
|
|
SetPlayerControlEnabled(GetOwner(), CON_GUIClick2, false);
|
2010-03-23 20:57:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-04-28 22:52:02 +00:00
|
|
|
func MenuClosed()
|
|
|
|
{
|
2010-12-08 00:56:48 +00:00
|
|
|
backpack_open = false;
|
2010-04-28 22:52:02 +00:00
|
|
|
SetMenu(nil);
|
|
|
|
}
|
|
|
|
|
2010-03-23 20:57:30 +00:00
|
|
|
func GetMenu()
|
|
|
|
{
|
|
|
|
return menu;
|
|
|
|
}
|
|
|
|
|
2010-04-09 15:06:28 +00:00
|
|
|
func CancelMenu()
|
|
|
|
{
|
|
|
|
if (menu) menu->Close();
|
|
|
|
}
|
|
|
|
|
2010-03-23 20:57:30 +00:00
|
|
|
func ReinitializeControls()
|
|
|
|
{
|
2010-03-23 21:18:43 +00:00
|
|
|
if(PlayerHasVirtualCursor(GetOwner()))
|
2010-03-23 20:57:30 +00:00
|
|
|
{
|
|
|
|
// if is aiming or in menu and no virtual cursor is there? Create one
|
|
|
|
if (!virtual_cursor)
|
|
|
|
if (menu || using)
|
2010-04-25 01:36:52 +00:00
|
|
|
VirtualCursor()->StartAim(this,false,menu);
|
2010-03-23 20:57:30 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// remove any virtual cursor
|
|
|
|
if (virtual_cursor)
|
|
|
|
virtual_cursor->RemoveObject();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-03-25 23:56:55 +00:00
|
|
|
/* Backpack control */
|
|
|
|
|
|
|
|
func Selected(object mnu, object mnu_item, bool alt)
|
|
|
|
{
|
|
|
|
var backpack_index = mnu_item->GetExtraData();
|
|
|
|
var hands_index = 0;
|
|
|
|
if (alt) hands_index = 1;
|
2010-09-04 19:26:36 +00:00
|
|
|
// Update menu
|
|
|
|
var show_new_item = GetItem(hands_index);
|
|
|
|
mnu_item->SetSymbol(show_new_item);
|
2010-03-25 23:56:55 +00:00
|
|
|
// swap index with backpack index
|
2010-09-13 15:27:48 +00:00
|
|
|
Switch2Items(hands_index, backpack_index);
|
2010-09-04 19:26:36 +00:00
|
|
|
return false;
|
2010-03-25 23:56:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* +++++++++++++++ Throwing, jumping +++++++++++++++ */
|
|
|
|
|
2009-12-29 13:44:16 +00:00
|
|
|
// Throwing
|
|
|
|
private func DoThrow(object obj, int angle)
|
|
|
|
{
|
2010-03-30 16:48:38 +00:00
|
|
|
// parameters...
|
|
|
|
var iX, iY, iR, iXDir, iYDir, iRDir;
|
|
|
|
iX = 8; if (!GetDir()) iX = -iX;
|
|
|
|
iY = Cos(angle,-8);
|
|
|
|
iR = Random(360);
|
|
|
|
iRDir = RandomX(-10,10);
|
|
|
|
|
2010-12-13 01:17:21 +00:00
|
|
|
iXDir = Sin(angle,this.ThrowSpeed);
|
|
|
|
iYDir = Cos(angle,-this.ThrowSpeed);
|
2010-03-30 16:48:38 +00:00
|
|
|
// throw boost (throws stronger upwards than downwards)
|
|
|
|
if (iYDir < 0) iYDir = iYDir * 13/10;
|
|
|
|
if (iYDir > 0) iYDir = iYDir * 8/10;
|
|
|
|
|
|
|
|
// add own velocity
|
2010-12-13 01:17:21 +00:00
|
|
|
iXDir += GetXDir(100)/2;
|
|
|
|
iYDir += GetYDir(100)/2;
|
2010-03-30 16:48:38 +00:00
|
|
|
|
|
|
|
// throw
|
2010-09-13 15:27:48 +00:00
|
|
|
obj->Exit(iX, iY, iR, 0, 0, iRDir);
|
2010-12-13 01:17:21 +00:00
|
|
|
obj->SetXDir(iXDir,100);
|
|
|
|
obj->SetYDir(iYDir,100);
|
2010-03-30 16:48:38 +00:00
|
|
|
|
|
|
|
return true;
|
2009-12-29 13:44:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// custom throw
|
|
|
|
public func ControlThrow(object target, int x, int y)
|
|
|
|
{
|
|
|
|
// standard throw after all
|
|
|
|
if (!x && !y) return false;
|
|
|
|
if (!target) return false;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
public func ControlJump()
|
|
|
|
{
|
|
|
|
var ydir = 0;
|
|
|
|
|
2010-02-02 15:09:56 +00:00
|
|
|
if (GetProcedure() == "WALK")
|
2009-12-29 13:44:16 +00:00
|
|
|
{
|
2010-12-12 22:49:18 +00:00
|
|
|
ydir = this.JumpSpeed;
|
2009-12-29 13:44:16 +00:00
|
|
|
}
|
2011-06-03 19:11:23 +00:00
|
|
|
|
|
|
|
if (InLiquid())
|
2009-12-29 13:44:16 +00:00
|
|
|
{
|
2010-04-27 20:41:27 +00:00
|
|
|
if (!GBackSemiSolid(0,-5))
|
2010-12-12 22:49:18 +00:00
|
|
|
ydir = BoundBy(this.JumpSpeed * 3 / 5, 240, 380);
|
2011-06-03 19:11:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (GetProcedure() == "SCALE")
|
|
|
|
{
|
|
|
|
ydir = this.JumpSpeed/2;
|
|
|
|
}
|
2009-12-29 13:44:16 +00:00
|
|
|
|
2010-12-08 15:46:54 +00:00
|
|
|
if (ydir && !Stuck())
|
2009-12-29 13:44:16 +00:00
|
|
|
{
|
|
|
|
SetPosition(GetX(),GetY()-1);
|
2011-06-03 19:11:23 +00:00
|
|
|
|
|
|
|
//Wall kick
|
|
|
|
if(GetProcedure() == "SCALE")
|
|
|
|
{
|
|
|
|
AddEffect("WallKick",this,1);
|
|
|
|
SetAction("Jump");
|
|
|
|
|
|
|
|
var xdir;
|
|
|
|
if(GetDir() == DIR_Right)
|
|
|
|
{
|
|
|
|
xdir = -1;
|
|
|
|
SetDir(DIR_Left);
|
|
|
|
}
|
|
|
|
else if(GetDir() == DIR_Left)
|
|
|
|
{
|
|
|
|
xdir = 1;
|
|
|
|
SetDir(DIR_Right);
|
|
|
|
}
|
|
|
|
|
|
|
|
SetYDir(-ydir * GetCon(), 100 * 100);
|
|
|
|
SetXDir(xdir * 17);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
//Normal jump
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SetAction("Jump");
|
|
|
|
SetYDir(-ydir * GetCon(), 100 * 100);
|
|
|
|
return true;
|
|
|
|
}
|
2009-12-29 13:44:16 +00:00
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2010-12-12 22:49:18 +00:00
|
|
|
|
2011-06-03 19:11:23 +00:00
|
|
|
func FxIsWallKickStart(object target, int num, bool temp)
|
|
|
|
{
|
|
|
|
return 1;
|
|
|
|
}
|