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
|
2012-12-25 11:19:23 +00:00
|
|
|
forwards to script.
|
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
|
|
|
*/
|
|
|
|
|
2012-12-25 11:19:23 +00:00
|
|
|
// make use of other sub-libraries
|
|
|
|
#include Library_Inventory
|
|
|
|
#include Library_ClonkInventoryControl
|
|
|
|
#include Library_ClonkGamepadControl
|
2010-03-25 23:56:55 +00:00
|
|
|
|
2012-04-22 16:44:28 +00:00
|
|
|
|
2012-12-25 11:19:23 +00:00
|
|
|
/* ++++++++++++++++++++++++ Clonk Inventory Control ++++++++++++++++++++++++ */
|
2012-10-07 13:44:01 +00:00
|
|
|
|
2012-12-25 11:19:23 +00:00
|
|
|
/*
|
|
|
|
used properties
|
|
|
|
this.control.hotkeypressed: used to determine if an interaction has already been handled by a hotkey (space + 1-9)
|
|
|
|
|
|
|
|
this.control.current_object: object that is being used at the moment
|
|
|
|
this.control.using_type: way of usage
|
|
|
|
this.control.alt: whether the current object is on mousebutton 2
|
|
|
|
this.control.mlastx: last x position of the cursor
|
|
|
|
this.control.mlasty: last y position of the cursor
|
|
|
|
this.control.noholdingcallbacks: whether to do HoldingUseControl callbacks
|
|
|
|
*/
|
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
|
|
|
public func MaxContentsCount() { return 7; } // Size of the clonks inventory
|
2012-12-25 11:19:23 +00:00
|
|
|
public func HandObjects() { return 1; } // Amount of hands to select items
|
2012-04-22 16:44:28 +00:00
|
|
|
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
|
|
|
|
2009-12-29 13:44:16 +00:00
|
|
|
/* ################################################# */
|
|
|
|
|
|
|
|
protected func Construction()
|
|
|
|
{
|
2012-12-25 11:19:23 +00:00
|
|
|
if(this.control == nil)
|
|
|
|
this.control = {};
|
|
|
|
this.control.hotkeypressed = false;
|
|
|
|
|
2010-03-23 20:57:30 +00:00
|
|
|
menu = nil;
|
2010-03-25 23:56:55 +00:00
|
|
|
|
2012-12-25 11:19:23 +00:00
|
|
|
this.control.alt = false;
|
|
|
|
this.control.current_object = nil;
|
|
|
|
this.control.using_type = nil;
|
2010-12-08 00:56:48 +00:00
|
|
|
|
2009-12-29 13:44:16 +00:00
|
|
|
return _inherited(...);
|
|
|
|
}
|
|
|
|
|
2012-12-25 11:19:23 +00:00
|
|
|
public func GetUsedObject() { return this.control.current_object; }
|
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-12-25 11:19:23 +00:00
|
|
|
|
2012-05-07 20:57:52 +00:00
|
|
|
return functions;
|
|
|
|
}
|
|
|
|
|
2010-03-25 23:56:55 +00:00
|
|
|
/* +++++++++++++++++++++++++++ Clonk Control +++++++++++++++++++++++++++ */
|
|
|
|
|
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
|
|
|
|
2012-03-22 19:26:06 +00:00
|
|
|
// some controls should only do something on release (everything that has to do with interaction)
|
2012-10-21 19:49:37 +00:00
|
|
|
if(ctrl == CON_Interact || ctrl == CON_PushEnter || ctrl == CON_Ungrab || ctrl == CON_GrabNext || ctrl == CON_Grab || ctrl == CON_Enter || ctrl == CON_Exit)
|
2012-03-22 19:26:06 +00:00
|
|
|
{
|
|
|
|
if(!release)
|
|
|
|
{
|
|
|
|
// this is needed to reset the hotkey-memory
|
2012-12-25 11:19:23 +00:00
|
|
|
this.control.hotkeypressed = false;
|
2012-03-22 19:26:06 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
// if the interaction-command has already been handled by a hotkey (else it'd double-interact)
|
2012-12-25 11:19:23 +00:00
|
|
|
else if(this.control.hotkeypressed)
|
2012-03-22 19:26:06 +00:00
|
|
|
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-06-17 19:37:13 +00:00
|
|
|
if(GetMenu())
|
|
|
|
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.
|
|
|
|
*/
|
2012-12-25 11:19:23 +00:00
|
|
|
if (this.control.current_object && ctrl == CON_Aim)
|
2009-12-29 13:44:16 +00:00
|
|
|
{
|
2012-12-25 11:19:23 +00:00
|
|
|
if (this.control.alt) ctrl = CON_UseAlt;
|
2010-02-04 01:08:21 +00:00
|
|
|
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)
|
|
|
|
{
|
2012-12-25 11:19:23 +00:00
|
|
|
this.control.mlastx = x;
|
|
|
|
this.control.mlasty = y;
|
2010-02-02 15:09:56 +00:00
|
|
|
}
|
2012-02-26 15:19:52 +00:00
|
|
|
|
2009-12-29 13:44:16 +00:00
|
|
|
var proc = GetProcedure();
|
|
|
|
|
2010-02-02 15:09:56 +00:00
|
|
|
// cancel usage
|
2012-12-25 11:19:23 +00:00
|
|
|
if (this.control.current_object && 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-12-25 11:19:23 +00:00
|
|
|
return _inherited(plr, ctrl, x, y, strength, repeat, release, ...);
|
2012-04-07 21:31:59 +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);
|
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-12-25 11:19:23 +00:00
|
|
|
var contents = this->GetHandItem(0);
|
|
|
|
var contents2 = this->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)
|
2012-12-25 11:19:23 +00:00
|
|
|
if (this.control.current_object == 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)
|
2012-12-25 11:19:23 +00:00
|
|
|
if (!this.control.current_object && (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
|
2012-12-25 11:19:23 +00:00
|
|
|
if ((contents || (release && this.control.current_object)) && (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
|
|
|
}
|
2012-12-25 11:19:23 +00:00
|
|
|
else if ((contents2 || (release && this.control.current_object)) && (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
|
|
|
|
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;
|
2012-12-25 11:19:23 +00:00
|
|
|
this.inventory.forced_ejection = contents; // used in Inventory.ocd
|
2012-02-27 15:24:34 +00:00
|
|
|
}
|
|
|
|
|
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
|
|
|
|
2012-10-20 17:32:16 +00:00
|
|
|
if (proc == "SCALE" || proc == "HANGLE" || proc == "SWIM")
|
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
|
2012-12-25 11:19:23 +00:00
|
|
|
return ObjectCommand("Throw", contents, this.control.mlastx, this.control.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;
|
2012-12-25 11:19:23 +00:00
|
|
|
this.inventory.forced_ejection = contents2; // used in Inventory.ocd
|
2012-02-27 15:24:34 +00:00
|
|
|
}
|
|
|
|
|
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
|
2012-12-25 11:19:23 +00:00
|
|
|
return ObjectCommand("Throw", contents2, this.control.mlastx, this.control.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
|
2012-12-25 11:19:23 +00:00
|
|
|
return _inherited(plr, ctrl, x, y, strength, repeat, release, ...);
|
2010-03-03 18:02:47 +00:00
|
|
|
}
|
|
|
|
|
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
|
|
|
{
|
2012-12-25 11:19:23 +00:00
|
|
|
if (!this.control.current_object) 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
|
2012-12-25 11:19:23 +00:00
|
|
|
CancelUseControl(this.control.mlastx, this.control.mlasty);
|
2009-12-29 13:44:16 +00:00
|
|
|
}
|
|
|
|
|
2010-10-09 17:08:58 +00:00
|
|
|
private func DetermineUsageType(object obj)
|
|
|
|
{
|
2012-12-25 11:19:23 +00:00
|
|
|
if(!obj) return nil;
|
2010-10-09 17:08:58 +00:00
|
|
|
// house
|
|
|
|
if (obj == Contained())
|
|
|
|
return C4D_Structure;
|
|
|
|
// object
|
2012-12-25 11:19:23 +00:00
|
|
|
if (obj->Contained() == this)
|
|
|
|
return C4D_Object;
|
2010-10-09 17:08:58 +00:00
|
|
|
// vehicle
|
|
|
|
var proc = GetProcedure();
|
|
|
|
if (obj == GetActionTarget())
|
|
|
|
if (proc == "ATTACH" && proc == "PUSH")
|
|
|
|
return C4D_Vehicle;
|
2012-12-25 11:19:23 +00:00
|
|
|
// unknown
|
2010-10-09 17:08:58 +00:00
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
2012-12-25 11:19:23 +00:00
|
|
|
private func GetUseCallString(string action)
|
|
|
|
{
|
2010-10-09 17:08:58 +00:00
|
|
|
// Control... or Contained...
|
|
|
|
var control = "Control";
|
2012-12-25 11:19:23 +00:00
|
|
|
if (this.control.using_type == C4D_Structure) control = "Contained";
|
2010-10-09 17:08:58 +00:00
|
|
|
// ..Use.. or ..UseAlt...
|
|
|
|
var estr = "";
|
2012-12-25 11:19:23 +00:00
|
|
|
if (this.control.alt && this.control.using_type != C4D_Object) estr = "Alt";
|
2010-10-09 17:08:58 +00:00
|
|
|
// 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
|
|
|
{
|
2012-12-25 11:19:23 +00:00
|
|
|
this.control.current_object = obj;
|
|
|
|
this.control.using_type = DetermineUsageType(obj);
|
|
|
|
this.control.alt = ctrl != CON_Use;
|
2010-10-09 17:08:58 +00:00
|
|
|
|
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);
|
2012-12-25 11:19:23 +00:00
|
|
|
this.control.noholdingcallbacks = handled;
|
2010-02-04 15:44:01 +00:00
|
|
|
}
|
2010-01-22 16:29:46 +00:00
|
|
|
if (!handled)
|
|
|
|
{
|
2012-12-25 11:19:23 +00:00
|
|
|
this.control.current_object = nil;
|
|
|
|
this.control.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
|
|
|
{
|
2012-12-25 11:19:23 +00:00
|
|
|
this.control.current_object = obj;
|
|
|
|
this.control.using_type = DetermineUsageType(obj);
|
|
|
|
this.control.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
|
2012-12-25 11:19:23 +00:00
|
|
|
var handled = obj->Call(GetUseCallString("Start"),this,this.control.mlastx,this.control.mlasty);
|
|
|
|
this.control.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();
|
2012-12-25 11:19:23 +00:00
|
|
|
if(horse && GetProcedure() == "ATTACH" && this.control.current_object != horse)
|
2010-10-09 17:08:58 +00:00
|
|
|
StopUseControl(x, y, horse, true);
|
2010-05-28 19:29:32 +00:00
|
|
|
|
2012-12-25 11:19:23 +00:00
|
|
|
return StopUseControl(x, y, this.control.current_object, 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);
|
2012-12-25 11:19:23 +00:00
|
|
|
if (obj == this.control.current_object)
|
2010-05-28 19:29:32 +00:00
|
|
|
{
|
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)
|
|
|
|
{
|
2012-12-25 11:19:23 +00:00
|
|
|
this.control.current_object = nil;
|
|
|
|
this.control.using_type = nil;
|
|
|
|
this.control.alt = false;
|
2011-02-13 20:49:02 +00:00
|
|
|
}
|
2012-12-25 11:19:23 +00:00
|
|
|
this.control.noholdingcallbacks = false;
|
2010-05-28 19:29:32 +00:00
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
2012-12-25 11:19:23 +00:00
|
|
|
mex = this.control.mlastx;
|
|
|
|
mey = this.control.mlasty;
|
2010-02-04 01:08:21 +00:00
|
|
|
}
|
|
|
|
|
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
|
2012-12-25 11:19:23 +00:00
|
|
|
// mounts (naturally). If turning vehicles just like that without issuing
|
2010-02-25 11:47:13 +00:00
|
|
|
// 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
|
|
|
|
2012-12-25 11:19:23 +00:00
|
|
|
var handled = obj->Call(GetUseCallString("Stop"),this,this.control.mlastx,this.control.mlasty);
|
2010-02-02 15:09:56 +00:00
|
|
|
if (!handled)
|
2012-12-25 11:19:23 +00:00
|
|
|
handled = obj->Call(GetUseCallString(),this,this.control.mlastx,this.control.mlasty);
|
2010-02-04 01:08:21 +00:00
|
|
|
|
2012-12-25 11:19:23 +00:00
|
|
|
if (obj == this.control.current_object)
|
2010-05-28 19:29:32 +00:00
|
|
|
{
|
|
|
|
VirtualCursor()->StopAim();
|
2011-02-13 20:49:02 +00:00
|
|
|
// see StopUseControl
|
|
|
|
if(handled != -1)
|
|
|
|
{
|
2012-12-25 11:19:23 +00:00
|
|
|
this.control.current_object = nil;
|
|
|
|
this.control.using_type = nil;
|
|
|
|
this.control.alt = false;
|
2011-02-13 20:49:02 +00:00
|
|
|
}
|
2012-12-25 11:19:23 +00:00
|
|
|
this.control.noholdingcallbacks = false;
|
2010-05-28 19:29:32 +00:00
|
|
|
}
|
2009-12-29 13:44:16 +00:00
|
|
|
|
|
|
|
return handled;
|
|
|
|
}
|
|
|
|
|
2010-03-22 15:40:54 +00:00
|
|
|
|
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
|
2012-12-25 11:19:23 +00:00
|
|
|
if (this.control.current_object)
|
2009-12-29 13:44:16 +00:00
|
|
|
{
|
2012-12-25 11:19:23 +00:00
|
|
|
if (ctrl == CON_Use && this.control.alt || ctrl == CON_UseAlt && !this.control.alt
|
|
|
|
|| ctrl == CON_UseDelayed && this.control.alt || ctrl == CON_UseAltDelayed && !this.control.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
|
|
|
}
|
2012-12-25 11:19:23 +00:00
|
|
|
else if (release && obj == this.control.current_object)
|
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
|
|
|
}
|
2012-12-25 11:19:23 +00:00
|
|
|
else if (release && obj == this.control.current_object)
|
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
|
|
|
}
|
2012-12-25 11:19:23 +00:00
|
|
|
else if (repeat && !this.control.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
|
|
|
|
{
|
2012-12-25 11:19:23 +00:00
|
|
|
// what about gamepad-deadzone?
|
2010-02-24 22:53:17 +00:00
|
|
|
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-02-04 01:08:21 +00:00
|
|
|
|
|
|
|
|
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
|
2012-12-25 11:19:23 +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)
|
|
|
|
{
|
2012-12-25 11:19:23 +00:00
|
|
|
menu->Close();
|
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)
|
|
|
|
{
|
2012-12-25 11:19:23 +00:00
|
|
|
RemoveVirtualCursor(); // for gamepads
|
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-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;
|
2012-10-21 22:11:24 +00:00
|
|
|
iX = 4; if (!GetDir()) iX = -iX;
|
|
|
|
iY = Cos(angle,-4);
|
2010-03-30 16:48:38 +00:00
|
|
|
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;
|
|
|
|
}
|