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)
|
2012-04-22 16:44:28 +00:00
|
|
|
|
|
|
|
Furthermore the clonk has a defined amount of "hands", defined by HandObjects().
|
|
|
|
The array 'use_objects' is a mapping of "hands" onto the inventory-slots.
|
|
|
|
The functions GetHandItem(i) returns the object in the "i"th hand.
|
|
|
|
|
|
|
|
Carryheavy is also handled here. When a clonk picks up a carryheavy object
|
|
|
|
it's saved in 'carryheavy'
|
2009-12-29 13:44:16 +00:00
|
|
|
*/
|
|
|
|
|
2010-03-25 23:56:55 +00:00
|
|
|
/* ++++++++++++++++++++++++ Clonk Inventory Control ++++++++++++++++++++++++ */
|
|
|
|
|
2012-04-22 16:44:28 +00:00
|
|
|
local inventory; // items in the inventory, array
|
|
|
|
local carryheavy; // object beeing carried with carryheavy
|
|
|
|
local use_objects; // hand-slots (mapping onto inventory)
|
|
|
|
|
|
|
|
local handslot_choice_pending; // used to determine if a slot-hotkey (1-9) has already been handled by a mouseclick
|
|
|
|
local hotkeypressed; // used to determine if an interaction has already been handled by a hotkey (space + 1-9)
|
2010-02-18 21:22:58 +00:00
|
|
|
|
2012-04-22 16:44:28 +00:00
|
|
|
local disableautosort; // used to get default-Collection-behaviour (see Collection2)
|
|
|
|
local force_collection; // used to pick stuff up, even though the hand-slots are all full (see RejectCollect + Collect with CON_Collect)
|
|
|
|
local forced_ejection; // used to recognize if an object was thrown out with or without the force-key (Shift). If not, next hand slot will be selected.
|
2010-02-18 21:22:58 +00:00
|
|
|
|
2009-12-29 13:44:16 +00:00
|
|
|
/* Item limit */
|
|
|
|
|
2012-04-22 16:44:28 +00:00
|
|
|
private func HandObjects() { return 2; } // How many "Hands" the clonk has
|
|
|
|
public func MaxContentsCount() { return 7; } // Size of the clonks inventory
|
|
|
|
public func NoStackedContentMenu() { return true; } // Contents-Menu shall display each object in a seperate slot
|
2009-12-29 13:44:16 +00:00
|
|
|
|
2012-04-22 16:44:28 +00:00
|
|
|
|
|
|
|
/** Get the 'i'th item in the inventory */
|
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];
|
|
|
|
}
|
|
|
|
|
2012-04-22 16:44:28 +00:00
|
|
|
/** Returns all items in the inventory */
|
2012-02-27 20:17:23 +00:00
|
|
|
public func GetItems()
|
|
|
|
{
|
|
|
|
var inv = inventory[:];
|
|
|
|
RemoveHoles(inv);
|
|
|
|
return inv;
|
|
|
|
}
|
|
|
|
|
2012-05-13 18:37:44 +00:00
|
|
|
/** Returns how many items are in the clonks inventory
|
|
|
|
Does not have to be the same as ContentCounts() because of objects with special handling, like CarryHeavy */
|
|
|
|
public func GetItemCount()
|
|
|
|
{
|
|
|
|
var count = 0;
|
|
|
|
for(var i=0; i < GetLength(inventory); i++)
|
|
|
|
if(inventory[i])
|
|
|
|
count++;
|
|
|
|
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
2012-04-22 16:44:28 +00:00
|
|
|
/** Get the 'i'th item in hands.
|
|
|
|
These are the items that will be used with use-commands. (Left mouse click, etc...) */
|
2012-02-26 00:48:58 +00:00
|
|
|
public func GetHandItem(int i)
|
|
|
|
{
|
2012-04-22 16:44:28 +00:00
|
|
|
// i is valid range
|
2012-02-26 00:48:58 +00:00
|
|
|
if (i >= GetLength(use_objects))
|
|
|
|
return nil;
|
|
|
|
if (i < 0) return nil;
|
2012-04-22 16:44:28 +00:00
|
|
|
|
|
|
|
// carrying a carry heavy item always returns said item. (he holds it in both hands, after all!)
|
|
|
|
if (IsCarryingHeavy())
|
|
|
|
return GetCarryHeavy();
|
2012-02-26 00:48:58 +00:00
|
|
|
|
|
|
|
return GetItem(use_objects[i]);
|
|
|
|
}
|
|
|
|
|
2012-04-22 16:44:28 +00:00
|
|
|
/** Set the 'hand'th use-item to the 'inv'th slot */
|
2012-02-26 00:48:58 +00:00
|
|
|
public func SetHandItemPos(int hand, int inv)
|
|
|
|
{
|
2012-04-29 14:26:32 +00:00
|
|
|
// indices are in range?
|
2012-02-26 00:48:58 +00:00
|
|
|
if(hand >= HandObjects() || inv >= MaxContentsCount())
|
|
|
|
return nil;
|
|
|
|
if(hand < 0 || inv < 0) return nil;
|
|
|
|
|
2012-04-22 16:44:28 +00:00
|
|
|
// can't use anything except carryheavy if carrying heavy object.
|
|
|
|
if(IsCarryingHeavy())
|
|
|
|
return nil;
|
|
|
|
|
2012-04-29 14:26:32 +00:00
|
|
|
// changing slots cancels using, if the slot with the used object is contained
|
|
|
|
if(using)
|
|
|
|
{
|
|
|
|
var used_slot = GetItemPos(using);
|
|
|
|
if(used_slot != nil)
|
|
|
|
if(used_slot == GetHandItemPos(hand) || used_slot == inv)
|
|
|
|
CancelUseControl(0,0);
|
|
|
|
}
|
|
|
|
|
2012-02-27 13:07:47 +00:00
|
|
|
// If the item is already selected, we can't hold it in another one too.
|
2012-02-28 19:18:52 +00:00
|
|
|
var hand2 = GetHandPosByItemPos(inv);
|
|
|
|
if(hand2 != nil)
|
2012-02-27 13:07:47 +00:00
|
|
|
{
|
2012-02-28 19:18:52 +00:00
|
|
|
// switch places
|
|
|
|
use_objects[hand2] = use_objects[hand];
|
|
|
|
use_objects[hand] = inv;
|
|
|
|
|
|
|
|
// additional callbacks
|
|
|
|
if(GetHandItem(hand2))
|
|
|
|
{
|
|
|
|
this->~OnSlotFull(hand2);
|
2012-05-06 16:24:56 +00:00
|
|
|
GetHandItem(hand2)->~Selection(this, hand2);
|
2012-02-28 19:18:52 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
this->~OnSlotEmpty(hand2);
|
2012-02-27 13:07:47 +00:00
|
|
|
}
|
2012-02-28 19:18:52 +00:00
|
|
|
else
|
|
|
|
use_objects[hand] = inv;
|
2012-02-26 00:48:58 +00:00
|
|
|
|
|
|
|
// call callbacks
|
|
|
|
if(GetItem(inv))
|
2012-02-28 18:52:15 +00:00
|
|
|
{
|
2012-02-26 00:48:58 +00:00
|
|
|
this->~OnSlotFull(hand);
|
2012-02-28 18:52:15 +00:00
|
|
|
GetItem(inv)->~Selection(this, hand);
|
|
|
|
}
|
2012-02-26 00:48:58 +00:00
|
|
|
else
|
2012-02-28 18:52:15 +00:00
|
|
|
{
|
2012-02-26 00:48:58 +00:00
|
|
|
this->~OnSlotEmpty(hand);
|
2012-02-28 18:52:15 +00:00
|
|
|
}
|
2012-02-26 15:19:52 +00:00
|
|
|
|
|
|
|
handslot_choice_pending = false;
|
2012-02-26 00:48:58 +00:00
|
|
|
}
|
|
|
|
|
2012-04-22 16:44:28 +00:00
|
|
|
/** Returns the position in the inventory of the 'i'th use item */
|
2012-02-26 00:48:58 +00:00
|
|
|
public func GetHandItemPos(int i)
|
|
|
|
{
|
|
|
|
if (i >= GetLength(use_objects))
|
|
|
|
return nil;
|
|
|
|
if (i < 0) return nil;
|
|
|
|
|
|
|
|
return use_objects[i];
|
|
|
|
}
|
|
|
|
|
2012-04-22 16:44:28 +00:00
|
|
|
/** Returns in which hand-slot the inventory-slot is */
|
2012-02-27 13:07:47 +00:00
|
|
|
private func GetHandPosByItemPos(int o) // sorry for the horribly long name --boni
|
2012-02-26 00:48:58 +00:00
|
|
|
{
|
|
|
|
for(var i=0; i < GetLength(use_objects); i++)
|
|
|
|
if(use_objects[i] == o)
|
|
|
|
return i;
|
|
|
|
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
2012-04-22 16:44:28 +00:00
|
|
|
/** Drops the item in the inventory slot, if any */
|
2012-02-27 15:24:34 +00:00
|
|
|
public func DropInventoryItem(int slot)
|
|
|
|
{
|
|
|
|
var obj = GetItem(slot);
|
|
|
|
if(!obj)
|
|
|
|
return nil;
|
|
|
|
|
|
|
|
this->SetCommand("Drop",obj);
|
|
|
|
}
|
2010-03-25 23:56:55 +00:00
|
|
|
|
2012-04-22 16:44:28 +00:00
|
|
|
/** Search for 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;
|
|
|
|
}
|
|
|
|
|
2012-04-22 16:44:28 +00:00
|
|
|
/** Switch two items in the clonk's inventory */
|
2010-03-25 23:56:55 +00:00
|
|
|
|
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();
|
|
|
|
|
2012-02-26 00:48:58 +00:00
|
|
|
var handone, handtwo;
|
|
|
|
handone = GetHandPosByItemPos(one);
|
|
|
|
handtwo = GetHandPosByItemPos(two);
|
|
|
|
|
2010-03-25 23:56:55 +00:00
|
|
|
// callbacks: (de)selection
|
2012-02-26 00:48:58 +00:00
|
|
|
if (handone != nil)
|
2010-05-08 00:02:17 +00:00
|
|
|
if (inventory[two]) inventory[two]->~Deselection(this,one);
|
2012-02-26 00:48:58 +00:00
|
|
|
if (handtwo != nil)
|
2010-05-08 00:02:17 +00:00
|
|
|
if (inventory[one]) inventory[one]->~Deselection(this,two);
|
|
|
|
|
2012-02-26 00:48:58 +00:00
|
|
|
if (handone != nil)
|
2010-05-08 00:02:17 +00:00
|
|
|
if (inventory[one]) inventory[one]->~Selection(this,one);
|
2012-02-26 00:48:58 +00:00
|
|
|
if (handtwo != nil)
|
2010-05-08 00:02:17 +00:00
|
|
|
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
|
2012-02-26 00:48:58 +00:00
|
|
|
if (handone != nil)
|
2010-03-25 23:56:55 +00:00
|
|
|
{
|
|
|
|
if (inventory[one])
|
2012-02-26 00:48:58 +00:00
|
|
|
this->~OnSlotFull(handone);
|
2010-03-25 23:56:55 +00:00
|
|
|
else
|
2012-02-26 00:48:58 +00:00
|
|
|
this->~OnSlotEmpty(handone);
|
2010-03-25 23:56:55 +00:00
|
|
|
}
|
2012-02-26 00:48:58 +00:00
|
|
|
if (handtwo != nil)
|
2010-03-25 23:56:55 +00:00
|
|
|
{
|
|
|
|
if (inventory[two])
|
2012-02-26 00:48:58 +00:00
|
|
|
this->~OnSlotFull(handtwo);
|
2010-03-25 23:56:55 +00:00
|
|
|
else
|
2012-02-26 00:48:58 +00:00
|
|
|
this->~OnSlotEmpty(handtwo);
|
2010-03-25 23:56:55 +00:00
|
|
|
}
|
2012-02-26 00:48:58 +00:00
|
|
|
|
|
|
|
this->~OnInventoryChange(one, two);
|
2009-12-30 15:50:25 +00:00
|
|
|
}
|
|
|
|
|
2012-04-22 16:44:28 +00:00
|
|
|
/* Overload of Collect function
|
|
|
|
Allows inventory/hands-Handling with forced-collection
|
|
|
|
*/
|
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;
|
2012-04-29 13:05:29 +00:00
|
|
|
if (pos == nil || item->~IsCarryHeavy())
|
2011-08-11 14:37:46 +00:00
|
|
|
{
|
|
|
|
success = _inherited(item,ignoreOCF);
|
|
|
|
force_collection = false;
|
|
|
|
return success;
|
|
|
|
}
|
2009-12-30 15:50:25 +00:00
|
|
|
// fail if the specified slot is full
|
2012-02-28 18:52:15 +00:00
|
|
|
if (GetItem(pos) == nil && pos >= 0 && pos < MaxContentsCount())
|
2009-12-30 15:50:25 +00:00
|
|
|
{
|
2011-08-11 14:37:46 +00:00
|
|
|
if (item)
|
|
|
|
{
|
|
|
|
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;
|
2012-02-26 00:48:58 +00:00
|
|
|
var handpos = GetHandPosByItemPos(pos);
|
|
|
|
// if the slot was a selected hand slot -> update it
|
|
|
|
if(handpos != nil)
|
|
|
|
{
|
|
|
|
this->~OnSlotFull(handpos);
|
|
|
|
}
|
2011-08-11 14:37:46 +00:00
|
|
|
}
|
|
|
|
}
|
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;
|
|
|
|
}
|
|
|
|
|
2009-12-29 13:44:16 +00:00
|
|
|
/* ################################################# */
|
|
|
|
|
|
|
|
protected func Construction()
|
|
|
|
{
|
2010-03-23 20:57:30 +00:00
|
|
|
menu = nil;
|
2010-03-25 23:56:55 +00:00
|
|
|
|
|
|
|
// inventory variables
|
|
|
|
inventory = CreateArray();
|
2012-02-26 00:48:58 +00:00
|
|
|
use_objects = CreateArray();
|
|
|
|
|
|
|
|
for(var i=0; i < HandObjects(); i++)
|
|
|
|
use_objects[i] = i;
|
2010-03-25 23:56:55 +00:00
|
|
|
|
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-12-08 00:56:48 +00:00
|
|
|
|
2009-12-29 13:44:16 +00:00
|
|
|
return _inherited(...);
|
|
|
|
}
|
|
|
|
|
|
|
|
protected func Collection2(object obj)
|
|
|
|
{
|
2012-04-07 21:31:59 +00:00
|
|
|
// carryheavy object gets special treatment
|
|
|
|
if(obj->~IsCarryHeavy()) // we can assume that we don't have a carryheavy object yet. If we do, Scripters are to blame.
|
|
|
|
{
|
2012-04-22 16:44:28 +00:00
|
|
|
if(obj != GetCarryHeavy())
|
2012-04-07 21:31:59 +00:00
|
|
|
CarryHeavy(obj);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
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;
|
2012-02-28 18:52:15 +00:00
|
|
|
var i;
|
2010-02-25 12:14:00 +00:00
|
|
|
|
2012-02-28 18:52:15 +00:00
|
|
|
// sort into selected hands if empty
|
|
|
|
for(i = 0; i < HandObjects(); i++)
|
2012-03-18 20:46:08 +00:00
|
|
|
if(!GetHandItem(i))
|
2012-02-28 18:52:15 +00:00
|
|
|
{
|
2012-03-18 20:46:08 +00:00
|
|
|
sel = GetHandItemPos(i);
|
2012-02-28 18:52:15 +00:00
|
|
|
inventory[sel] = obj;
|
|
|
|
success = true;
|
2012-03-18 21:50:03 +00:00
|
|
|
break;
|
2012-02-28 18:52:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// otherwise, first empty slot
|
|
|
|
if(!success)
|
2009-12-29 13:44:16 +00:00
|
|
|
{
|
2012-02-28 18:52:15 +00:00
|
|
|
for(var i = 0; i < MaxContentsCount(); ++i)
|
2009-12-29 13:44:16 +00:00
|
|
|
{
|
2012-02-28 18:52:15 +00:00
|
|
|
if (!GetItem(i))
|
2009-12-29 13:44:16 +00:00
|
|
|
{
|
2012-02-28 18:52:15 +00:00
|
|
|
sel = i;
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-02-28 18:52:15 +00:00
|
|
|
|
2010-03-25 23:56:55 +00:00
|
|
|
// callbacks
|
2010-03-03 18:02:47 +00:00
|
|
|
if (success)
|
2012-02-26 00:48:58 +00:00
|
|
|
{
|
|
|
|
var handpos = GetHandPosByItemPos(sel);
|
|
|
|
// if the slot was a selected hand slot -> update it
|
|
|
|
if(handpos != nil)
|
2012-02-28 18:52:15 +00:00
|
|
|
{
|
2012-02-26 00:48:58 +00:00
|
|
|
this->~OnSlotFull(handpos);
|
2012-02-28 18:52:15 +00:00
|
|
|
obj->~Selection(this, handpos);
|
|
|
|
}
|
2012-02-26 00:48:58 +00:00
|
|
|
}
|
2012-02-28 18:52:15 +00:00
|
|
|
|
2009-12-29 13:44:16 +00:00
|
|
|
|
|
|
|
return _inherited(obj,...);
|
|
|
|
}
|
|
|
|
|
|
|
|
protected func Ejection(object obj)
|
|
|
|
{
|
2012-04-07 21:31:59 +00:00
|
|
|
// carry heavy special treatment
|
2012-04-22 16:44:28 +00:00
|
|
|
if(obj == GetCarryHeavy())
|
2012-04-07 21:31:59 +00:00
|
|
|
{
|
|
|
|
StopCarryHeavy();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
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;
|
2012-02-28 18:52:15 +00:00
|
|
|
|
2010-02-25 12:14:00 +00:00
|
|
|
for(var item in inventory)
|
2012-02-28 18:52:15 +00:00
|
|
|
{
|
|
|
|
if (obj == item)
|
|
|
|
{
|
2010-01-22 16:29:46 +00:00
|
|
|
inventory[i] = nil;
|
2010-02-25 12:14:00 +00:00
|
|
|
success = true;
|
2010-01-22 16:29:46 +00:00
|
|
|
break;
|
2012-02-28 18:52:15 +00:00
|
|
|
}
|
|
|
|
++i;
|
|
|
|
}
|
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)
|
2012-02-26 00:48:58 +00:00
|
|
|
{
|
|
|
|
var handpos = GetHandPosByItemPos(i);
|
|
|
|
// if the slot was a selected hand slot -> update it
|
|
|
|
if(handpos != nil)
|
2012-02-27 15:24:34 +00:00
|
|
|
{
|
|
|
|
// if it was a forced ejection, the hand will remain empty
|
|
|
|
if(forced_ejection == obj)
|
2012-02-28 18:52:15 +00:00
|
|
|
{
|
2012-02-27 15:24:34 +00:00
|
|
|
this->~OnSlotEmpty(handpos);
|
2012-02-28 18:52:15 +00:00
|
|
|
obj->~Deselection(this, handpos);
|
|
|
|
}
|
2012-02-27 15:24:34 +00:00
|
|
|
// else we'll select the next full slot
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// look for following non-selected non-free slots
|
|
|
|
var found_slot = false;
|
|
|
|
for(var j=i; j < MaxContentsCount(); j++)
|
|
|
|
if(GetItem(j) && !GetHandPosByItemPos(j))
|
|
|
|
{
|
|
|
|
found_slot = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(found_slot)
|
|
|
|
SetHandItemPos(handpos, j); // SetHandItemPos handles the missing callbacks
|
|
|
|
// no full next slot could be found. we'll stay at the same, and empty.
|
|
|
|
else
|
2012-02-28 18:52:15 +00:00
|
|
|
{
|
2012-02-27 15:24:34 +00:00
|
|
|
this->~OnSlotEmpty(handpos);
|
2012-02-28 18:52:15 +00:00
|
|
|
obj->~Deselection(this, handpos);
|
|
|
|
}
|
2012-02-27 15:24:34 +00:00
|
|
|
}
|
|
|
|
}
|
2012-02-26 00:48:58 +00:00
|
|
|
}
|
2009-12-29 13:44:16 +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.
|
2012-02-28 18:52:15 +00:00
|
|
|
var inventory_count = 0;
|
|
|
|
for(var io in inventory)
|
|
|
|
if(io != nil)
|
|
|
|
inventory_count++;
|
|
|
|
|
|
|
|
if (ContentsCount() > inventory_count && !GetItem(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
|
|
|
{
|
2012-02-28 18:52:15 +00:00
|
|
|
var o = Contents(c);
|
2012-04-13 18:24:41 +00:00
|
|
|
if(o->~IsCarryHeavy())
|
|
|
|
continue;
|
2012-02-28 18:52:15 +00:00
|
|
|
if (GetItemPos(o) == nil)
|
2010-02-18 21:22:58 +00:00
|
|
|
{
|
|
|
|
// found it! Collect it properly
|
2012-02-28 18:52:15 +00:00
|
|
|
inventory[i] = o;
|
2010-02-18 21:22:58 +00:00
|
|
|
|
2012-02-26 00:48:58 +00:00
|
|
|
var handpos = GetHandPosByItemPos(i);
|
|
|
|
// if the slot was a selected hand slot -> update it
|
|
|
|
if(handpos != nil)
|
2012-02-28 18:52:15 +00:00
|
|
|
{
|
2012-02-26 00:48:58 +00:00
|
|
|
this->~OnSlotFull(handpos);
|
2012-02-28 18:52:15 +00:00
|
|
|
o->~Selection(this, handpos);
|
|
|
|
}
|
2010-02-18 21:22:58 +00:00
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-12-29 13:44:16 +00:00
|
|
|
_inherited(obj,...);
|
|
|
|
}
|
|
|
|
|
2012-04-07 21:31:59 +00:00
|
|
|
protected func ContentsDestruction(object obj)
|
2012-03-21 20:55:34 +00:00
|
|
|
{
|
|
|
|
// tell the Hud that something changed
|
|
|
|
this->~OnInventoryChange();
|
|
|
|
|
2012-04-07 21:31:59 +00:00
|
|
|
// check if it was carryheavy
|
2012-04-22 16:44:28 +00:00
|
|
|
if(obj == GetCarryHeavy())
|
2012-04-07 21:31:59 +00:00
|
|
|
{
|
|
|
|
StopCarryHeavy();
|
|
|
|
}
|
|
|
|
|
2012-03-21 20:55:34 +00:00
|
|
|
_inherited(...);
|
|
|
|
}
|
|
|
|
|
2009-12-29 13:44:16 +00:00
|
|
|
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
|
|
|
|
2012-05-13 18:37:44 +00:00
|
|
|
// Carry heavy only gets picked up if none held already
|
2012-04-07 21:31:59 +00:00
|
|
|
if(obj->~IsCarryHeavy())
|
|
|
|
{
|
|
|
|
if(IsCarryingHeavy())
|
|
|
|
return true;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-26 21:03:12 +00:00
|
|
|
//No collection if the clonk is carrying a 'carry-heavy' object
|
2012-04-07 21:31:59 +00:00
|
|
|
// todo: does this still make sense with carry heavy not beeing in inventory and new inventory in general?
|
|
|
|
if(IsCarryingHeavy() && !force_collection) 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)
|
2012-02-26 13:13:14 +00:00
|
|
|
if (GetHandItem(0) && GetHandItem(1))
|
2010-03-25 23:56:55 +00:00
|
|
|
return true;
|
|
|
|
|
2009-12-29 13:44:16 +00:00
|
|
|
return _inherited(objid,obj,...);
|
|
|
|
}
|
|
|
|
|
2011-12-28 10:49:38 +00:00
|
|
|
// To allow transfer of contents which are not allowed through collection.
|
|
|
|
public func AllowTransfer(object obj)
|
|
|
|
{
|
|
|
|
// Only check max contents.
|
2012-05-13 18:37:44 +00:00
|
|
|
if (GetItemCount() >= MaxContentsCount())
|
2011-12-28 10:49:38 +00:00
|
|
|
return false;
|
|
|
|
|
2012-04-22 16:44:28 +00:00
|
|
|
// don't allow picking up multiple carryheavy-objects
|
|
|
|
if(IsCarryingHeavy() && obj->~IsCarryHeavy())
|
2012-04-13 18:24:41 +00:00
|
|
|
return false;
|
|
|
|
|
2011-12-28 10:49:38 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-11-25 18:03:19 +00:00
|
|
|
public func GetUsedObject() { return using; }
|
|
|
|
|
2012-04-07 21:31:59 +00:00
|
|
|
|
|
|
|
|
|
|
|
/* Carry heavy stuff */
|
|
|
|
|
2012-04-22 16:44:28 +00:00
|
|
|
/** Tells the clonk that he is carrying the given carry heavy object */
|
2012-04-07 21:31:59 +00:00
|
|
|
public func CarryHeavy(object target)
|
|
|
|
{
|
|
|
|
if(!target)
|
|
|
|
return;
|
2012-04-22 16:44:28 +00:00
|
|
|
// actually.. is it a carry heavy object?
|
|
|
|
if(!target->~IsCarryHeavy())
|
|
|
|
return;
|
|
|
|
// only if not carrying a heavy objcet already
|
2012-04-07 21:31:59 +00:00
|
|
|
if(IsCarryingHeavy())
|
|
|
|
return;
|
2012-04-22 16:44:28 +00:00
|
|
|
|
2012-04-07 21:31:59 +00:00
|
|
|
carryheavy = target;
|
|
|
|
|
|
|
|
if(target->Contained() != this)
|
|
|
|
target->Enter(this);
|
|
|
|
|
|
|
|
// notify UI about carryheavy pickup
|
|
|
|
this->~OnCarryHeavyChange(carryheavy);
|
|
|
|
|
|
|
|
// Update attach stuff
|
2012-04-14 14:51:30 +00:00
|
|
|
this->~OnSlotFull();
|
2012-04-07 21:31:59 +00:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-04-22 16:44:28 +00:00
|
|
|
/** Drops the carried heavy object, if any */
|
|
|
|
public func DropCarryHeavy()
|
|
|
|
{
|
|
|
|
// only if actually possible
|
|
|
|
if(!IsCarryingHeavy())
|
|
|
|
return;
|
|
|
|
|
|
|
|
GetCarryHeavy()->Drop();
|
|
|
|
StopCarryHeavy();
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Internal function to clear carryheavy-status
|
2012-04-07 21:31:59 +00:00
|
|
|
private func StopCarryHeavy()
|
|
|
|
{
|
2012-04-22 16:44:28 +00:00
|
|
|
if(!IsCarryingHeavy())
|
2012-04-07 21:31:59 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
carryheavy = nil;
|
|
|
|
this->~OnCarryHeavyChange(nil);
|
2012-04-13 18:24:41 +00:00
|
|
|
this->~OnSlotEmpty();
|
2012-04-07 21:31:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public func GetCarryHeavy() { return carryheavy; }
|
|
|
|
|
|
|
|
public func IsCarryingHeavy() { return carryheavy != nil; }
|
|
|
|
|
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
|
|
|
|
2012-05-07 20:57:52 +00:00
|
|
|
/** Returns additional interactions the clonk possesses as an array of function pointers.
|
|
|
|
Returned Proplist contains:
|
|
|
|
Fn = Name of the function to call
|
|
|
|
Object = object to call the function in. Will also be displayed on the interaction-button
|
|
|
|
Description = a description of what the interaction does
|
|
|
|
IconID = ID of the definition that contains the icon (like GetInteractionMetaInfo)
|
|
|
|
IconName = Namo of the graphic for teh icon (like GetInteractionMetaInfo)
|
2012-05-08 18:26:50 +00:00
|
|
|
[Priority] = Where to sort in in the interaction-list. 0=front, 1=after script, 2=after vehicles, >=3=at the end, nil equals 3
|
2012-05-07 20:57:52 +00:00
|
|
|
*/
|
|
|
|
public func GetExtraInteractions()
|
|
|
|
{
|
|
|
|
var functions = CreateArray();
|
2012-05-08 18:27:24 +00:00
|
|
|
|
|
|
|
// flipping construction-preview
|
|
|
|
var effect;
|
|
|
|
if(effect = GetEffect("ControlConstructionPreview", this))
|
|
|
|
{
|
|
|
|
if(effect.flipable)
|
|
|
|
PushBack(functions, {Fn = "Flip", Description=ConstructionPreviewer->GetFlipDescription(), Object=effect.preview, IconID=ConstructionPreviewer_IconFlip, Priority=0});
|
|
|
|
}
|
|
|
|
|
2012-05-08 18:26:50 +00:00
|
|
|
// dropping carry heavy
|
2012-05-07 20:57:52 +00:00
|
|
|
if(IsCarryingHeavy() && GetAction() == "Walk")
|
|
|
|
{
|
|
|
|
var ch = GetCarryHeavy();
|
2012-05-08 18:26:50 +00:00
|
|
|
PushBack(functions, {Fn = "Drop", Description=ch->GetDropDescription(), Object=ch, IconName="LetGo", IconID=GUI_ObjectSelector, Priority=1});
|
2012-05-07 20:57:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return functions;
|
|
|
|
}
|
|
|
|
|
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;
|
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)
|
|
|
|
{
|
2012-01-01 23:00:13 +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
|
|
|
|
2012-03-22 19:26:06 +00:00
|
|
|
// some controls should only do something on release (everything that has to do with interaction)
|
|
|
|
if(ctrl == CON_Interact || ctrl == CON_PushEnter || ctrl == CON_Ungrab || ctrl == CON_Grab || ctrl == CON_Enter || ctrl == CON_Exit)
|
|
|
|
{
|
|
|
|
if(!release)
|
|
|
|
{
|
|
|
|
// this is needed to reset the hotkey-memory
|
|
|
|
hotkeypressed = false;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
// if the interaction-command has already been handled by a hotkey (else it'd double-interact)
|
|
|
|
else if(hotkeypressed)
|
|
|
|
return false;
|
2012-04-14 16:41:56 +00:00
|
|
|
// check if we can handle it by simply accessing the first actionbar item (for consistency)
|
|
|
|
else
|
|
|
|
{
|
2012-04-14 20:53:36 +00:00
|
|
|
if(GetMenu())
|
|
|
|
if(!GetMenu()->~Uncloseable())
|
|
|
|
return CancelMenu();
|
|
|
|
|
2012-04-14 16:41:56 +00:00
|
|
|
if(this->~ControlHotkey(0))
|
2012-04-14 20:53:36 +00:00
|
|
|
return true;
|
2012-04-14 16:41:56 +00:00
|
|
|
}
|
2012-03-22 19:26:06 +00:00
|
|
|
}
|
|
|
|
|
2012-01-01 23:00:13 +00:00
|
|
|
// Contents menu
|
|
|
|
if (ctrl == CON_Contents)
|
2011-12-08 18:57:14 +00:00
|
|
|
{
|
2012-01-01 23:00:13 +00:00
|
|
|
// Close any menu if open.
|
2011-12-08 18:57:14 +00:00
|
|
|
if (GetMenu())
|
|
|
|
{
|
2012-04-03 13:51:38 +00:00
|
|
|
// Uncloseable menu?
|
|
|
|
if (GetMenu()->~Uncloseable()) return true;
|
|
|
|
|
2012-01-01 23:00:13 +00:00
|
|
|
var is_content = GetMenu()->~IsContentMenu();
|
2012-04-14 20:53:36 +00:00
|
|
|
CancelMenu();
|
2012-01-01 23:00:13 +00:00
|
|
|
// If contents menu, don't open new one and return.
|
|
|
|
if (is_content)
|
2011-12-08 18:57:14 +00:00
|
|
|
return true;
|
2010-03-25 23:56:55 +00:00
|
|
|
}
|
2012-01-01 23:00:13 +00:00
|
|
|
// Open contents menu.
|
2011-12-08 18:57:14 +00:00
|
|
|
CancelUse();
|
|
|
|
CreateContentsMenus();
|
|
|
|
// CreateContentsMenus calls SetMenu(this) in the clonk
|
|
|
|
// so after this call menu = the created menu
|
2012-01-01 23:00:13 +00:00
|
|
|
GetMenu()->Show();
|
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;
|
2012-02-26 00:48:58 +00:00
|
|
|
if (ctrl == CON_InteractionHotkey0) hot = 10;
|
|
|
|
if (ctrl == CON_InteractionHotkey1) hot = 1;
|
|
|
|
if (ctrl == CON_InteractionHotkey2) hot = 2;
|
|
|
|
if (ctrl == CON_InteractionHotkey3) hot = 3;
|
|
|
|
if (ctrl == CON_InteractionHotkey4) hot = 4;
|
|
|
|
if (ctrl == CON_InteractionHotkey5) hot = 5;
|
|
|
|
if (ctrl == CON_InteractionHotkey6) hot = 6;
|
|
|
|
if (ctrl == CON_InteractionHotkey7) hot = 7;
|
|
|
|
if (ctrl == CON_InteractionHotkey8) hot = 8;
|
|
|
|
if (ctrl == CON_InteractionHotkey9) hot = 9;
|
|
|
|
|
|
|
|
if (hot > 0)
|
|
|
|
{
|
2012-03-22 19:26:06 +00:00
|
|
|
hotkeypressed = true;
|
2012-02-26 13:26:23 +00:00
|
|
|
this->~ControlHotkey(hot-1);
|
2012-02-26 00:48:58 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-02-27 15:24:34 +00:00
|
|
|
// dropping items via hotkey
|
|
|
|
hot = 0;
|
|
|
|
if (ctrl == CON_DropHotkey0) hot = 10;
|
|
|
|
if (ctrl == CON_DropHotkey1) hot = 1;
|
|
|
|
if (ctrl == CON_DropHotkey2) hot = 2;
|
|
|
|
if (ctrl == CON_DropHotkey3) hot = 3;
|
|
|
|
if (ctrl == CON_DropHotkey4) hot = 4;
|
|
|
|
if (ctrl == CON_DropHotkey5) hot = 5;
|
|
|
|
if (ctrl == CON_DropHotkey6) hot = 6;
|
|
|
|
if (ctrl == CON_DropHotkey7) hot = 7;
|
|
|
|
if (ctrl == CON_DropHotkey8) hot = 8;
|
|
|
|
if (ctrl == CON_DropHotkey9) hot = 9;
|
|
|
|
|
|
|
|
if (hot > 0)
|
|
|
|
{
|
|
|
|
this->~DropInventoryItem(hot-1);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-02-26 15:19:52 +00:00
|
|
|
// this wall of text is called when 1-0 is beeing held, and left or right mouse button is pressed.
|
|
|
|
var hand = 0;
|
|
|
|
hot = 0;
|
|
|
|
if (ctrl == CON_Hotkey0Select) hot = 10;
|
|
|
|
if (ctrl == CON_Hotkey1Select) hot = 1;
|
|
|
|
if (ctrl == CON_Hotkey2Select) hot = 2;
|
|
|
|
if (ctrl == CON_Hotkey3Select) hot = 3;
|
|
|
|
if (ctrl == CON_Hotkey4Select) hot = 4;
|
|
|
|
if (ctrl == CON_Hotkey5Select) hot = 5;
|
|
|
|
if (ctrl == CON_Hotkey6Select) hot = 6;
|
|
|
|
if (ctrl == CON_Hotkey7Select) hot = 7;
|
|
|
|
if (ctrl == CON_Hotkey8Select) hot = 8;
|
|
|
|
if (ctrl == CON_Hotkey9Select) hot = 9;
|
|
|
|
if (ctrl == CON_Hotkey0SelectAlt) {hot = 10; hand=1; }
|
|
|
|
if (ctrl == CON_Hotkey1SelectAlt) {hot = 1; hand=1; }
|
|
|
|
if (ctrl == CON_Hotkey2SelectAlt) {hot = 2; hand=1; }
|
|
|
|
if (ctrl == CON_Hotkey3SelectAlt) {hot = 3; hand=1; }
|
|
|
|
if (ctrl == CON_Hotkey4SelectAlt) {hot = 4; hand=1; }
|
|
|
|
if (ctrl == CON_Hotkey5SelectAlt) {hot = 5; hand=1; }
|
|
|
|
if (ctrl == CON_Hotkey6SelectAlt) {hot = 6; hand=1; }
|
|
|
|
if (ctrl == CON_Hotkey7SelectAlt) {hot = 7; hand=1; }
|
|
|
|
if (ctrl == CON_Hotkey8SelectAlt) {hot = 8; hand=1; }
|
|
|
|
if (ctrl == CON_Hotkey9SelectAlt) {hot = 9; hand=1; }
|
|
|
|
|
|
|
|
if(hot > 0 && hot <= MaxContentsCount())
|
|
|
|
{
|
|
|
|
SetHandItemPos(hand, hot-1);
|
|
|
|
this->~OnInventoryHotkeyRelease(hot-1);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-02-26 00:48:58 +00:00
|
|
|
// inventory
|
|
|
|
hot = 0;
|
2009-12-29 13:44:16 +00:00
|
|
|
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;
|
|
|
|
|
2012-02-26 15:19:52 +00:00
|
|
|
// only the last-pressed key is taken into consideration.
|
|
|
|
// if 2 hotkeys are held, the earlier one is beeing treated as released
|
2012-02-26 00:48:58 +00:00
|
|
|
if (hot > 0 && hot <= MaxContentsCount())
|
2010-03-22 15:40:54 +00:00
|
|
|
{
|
2012-02-26 15:19:52 +00:00
|
|
|
// if released, we chose, if not chosen already
|
|
|
|
if(release)
|
|
|
|
{
|
|
|
|
if(handslot_choice_pending == hot)
|
|
|
|
{
|
|
|
|
SetHandItemPos(0, hot-1);
|
|
|
|
this->~OnInventoryHotkeyRelease(hot-1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// else we just highlight
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if(handslot_choice_pending)
|
|
|
|
{
|
|
|
|
this->~OnInventoryHotkeyRelease(handslot_choice_pending-1);
|
|
|
|
}
|
|
|
|
handslot_choice_pending = hot;
|
|
|
|
this->~OnInventoryHotkeyPress(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
|
2012-04-07 21:31:59 +00:00
|
|
|
if (using && ctrl == CON_Ungrab)
|
2010-02-02 15:09:56 +00:00
|
|
|
{
|
|
|
|
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
|
|
|
|
2012-04-07 21:31:59 +00:00
|
|
|
// Interact controls
|
|
|
|
if(ctrl == CON_Interact)
|
|
|
|
{
|
|
|
|
if(ObjectControlInteract(plr,ctrl))
|
|
|
|
return true;
|
2012-04-13 15:49:09 +00:00
|
|
|
else if(IsCarryingHeavy() && GetAction() == "Walk")
|
2012-04-07 21:31:59 +00:00
|
|
|
{
|
2012-04-22 16:44:28 +00:00
|
|
|
DropCarryHeavy();
|
2012-04-07 21:31:59 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
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);
|
2012-04-07 21:31:59 +00:00
|
|
|
|
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
|
|
|
|
2012-02-26 00:48:58 +00:00
|
|
|
var contents = GetHandItem(0);
|
|
|
|
var contents2 = GetHandItem(1);
|
2011-01-03 20:15:19 +00:00
|
|
|
|
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
|
2012-02-27 15:24:34 +00:00
|
|
|
// only act on press, not release
|
|
|
|
if (!house && (!vehicle || proc == "ATTACH") && !release)
|
2009-12-29 13:44:16 +00:00
|
|
|
{
|
|
|
|
if (contents)
|
|
|
|
{
|
2012-02-27 15:24:34 +00:00
|
|
|
// special treatmant so that we know it's a forced throw
|
|
|
|
if(ctrl == CON_ForcedThrow)
|
|
|
|
{
|
|
|
|
ctrl = CON_Throw;
|
|
|
|
forced_ejection = contents;
|
|
|
|
}
|
|
|
|
|
2009-12-29 13:44:16 +00:00
|
|
|
// throw
|
|
|
|
if (ctrl == CON_Throw)
|
|
|
|
{
|
2011-02-13 20:37:58 +00:00
|
|
|
CancelUse();
|
2012-02-27 15:24:34 +00:00
|
|
|
|
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)
|
|
|
|
{
|
2012-02-27 15:24:34 +00:00
|
|
|
// special treatmant so that we know it's a forced throw
|
|
|
|
if(ctrl == CON_ForcedThrowAlt)
|
|
|
|
{
|
|
|
|
ctrl = CON_ThrowAlt;
|
|
|
|
forced_ejection = contents2;
|
|
|
|
}
|
|
|
|
|
2009-12-29 13:44:16 +00:00
|
|
|
// 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
|
2012-02-26 14:54:09 +00:00
|
|
|
if (command == "Throw") return this->~ControlThrow(target,tx,ty);
|
|
|
|
else if (command == "Jump") return this->~ControlJump();
|
2009-12-29 13:44:16 +00:00
|
|
|
// else standard command
|
2012-02-26 14:54:09 +00:00
|
|
|
else return 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 */
|
|
|
|
if (!PlayerHasVirtualCursor(GetOwner()))
|
2012-01-19 14:03:36 +00:00
|
|
|
return true;
|
2010-04-25 01:36:52 +00:00
|
|
|
|
|
|
|
// 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)
|
2012-02-01 21:29:49 +00:00
|
|
|
this->GetMenu()->~OnMouseClick(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)
|
|
|
|
{
|
|
|
|
// 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)
|
2012-01-05 21:10:41 +00:00
|
|
|
{
|
2010-06-24 19:55:01 +00:00
|
|
|
if (interactable->~Interact(this))
|
2012-01-05 21:10:41 +00:00
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
2010-06-24 19:55:01 +00:00
|
|
|
}
|
|
|
|
|
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
|
2011-12-30 17:53:25 +00:00
|
|
|
if (menu == m && m)
|
2010-05-07 22:10:09 +00:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2011-12-08 18:57:14 +00:00
|
|
|
// no multiple menus: close old one
|
2010-03-23 20:57:30 +00:00
|
|
|
if (menu && m)
|
|
|
|
{
|
2011-12-08 18:57:14 +00:00
|
|
|
menu->RemoveObject();
|
2010-03-23 20:57:30 +00:00
|
|
|
}
|
|
|
|
// 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-12-30 17:53:25 +00:00
|
|
|
if (menu->~CursorUpdatesEnabled())
|
2011-11-20 21:09:53 +00:00
|
|
|
SetPlayerControlEnabled(GetOwner(), CON_GUICursor, true);
|
2011-12-30 17:53:25 +00:00
|
|
|
|
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()
|
|
|
|
{
|
|
|
|
SetMenu(nil);
|
|
|
|
}
|
|
|
|
|
2010-03-23 20:57:30 +00:00
|
|
|
func GetMenu()
|
|
|
|
{
|
|
|
|
return menu;
|
|
|
|
}
|
|
|
|
|
2010-04-09 15:06:28 +00:00
|
|
|
func CancelMenu()
|
|
|
|
{
|
2012-04-14 20:53:36 +00:00
|
|
|
if (menu)
|
|
|
|
{
|
|
|
|
menu->Close();
|
|
|
|
SetMenu(nil);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
2010-04-09 15:06:28 +00:00
|
|
|
}
|
|
|
|
|
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-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;
|
|
|
|
}
|