forked from Mirrors/openclonk
506 lines
11 KiB
C
506 lines
11 KiB
C
/**
|
|
HUD Object Selector
|
|
For each inventory item (and each vehicle, house etc on the same pos)
|
|
one of this objects exists in the bottom bar. If clicked, the associated
|
|
object is selected (inventory item is selected, vehicle is grabbed
|
|
or ungrabbed, house is entered or exited...).
|
|
|
|
HUD elements are passive, they don't update their status by themselves
|
|
but rely on the clonk to update their status.
|
|
|
|
This object works only for crew members that included the standard clonk
|
|
controls (see Libraries.c4d/ClonkControl.c4d)
|
|
|
|
@authors Newton
|
|
|
|
*/
|
|
|
|
/*
|
|
usage of layers:
|
|
-----------------
|
|
layer 0 - unused
|
|
layer 1 - title
|
|
layer 2 - actionicon
|
|
|
|
layer 12 - hotkey
|
|
|
|
*/
|
|
|
|
local selected, crew, hotkey, myobject, actiontype, subselector, position, modus;
|
|
local extra; // function to call and desc for extra-types
|
|
|
|
static const ACTIONTYPE_INVENTORY = 0;
|
|
static const ACTIONTYPE_VEHICLE = 1;
|
|
static const ACTIONTYPE_STRUCTURE = 2;
|
|
static const ACTIONTYPE_SCRIPT = 3;
|
|
static const ACTIONTYPE_EXTRA = 4;
|
|
|
|
private func HandSize() { return 400; }
|
|
private func IconSize() { return 500; }
|
|
|
|
protected func Construction()
|
|
{
|
|
_inherited();
|
|
|
|
selected = 0;
|
|
hotkey = 0;
|
|
position = 0;
|
|
myobject = nil;
|
|
subselector = nil;
|
|
|
|
// parallaxity
|
|
this.Parallaxity = [0,0];
|
|
// visibility
|
|
this.Visibility = VIS_None;
|
|
}
|
|
|
|
protected func Destruction()
|
|
{
|
|
if(subselector)
|
|
subselector->RemoveObject();
|
|
}
|
|
|
|
public func ShowsItem()
|
|
{
|
|
if(myobject) return true;
|
|
else return false;
|
|
}
|
|
|
|
public func MouseSelectionAlt(int plr)
|
|
{
|
|
if (!myobject) return;
|
|
|
|
var desc = myobject.UsageHelp;
|
|
if (!desc) desc = myobject.Description; // fall back to general description
|
|
|
|
// close other messages...
|
|
crew->OnDisplayInfoMessage();
|
|
|
|
if (desc)
|
|
{
|
|
var msg = Format("<c ff0000>%s</c>", desc);
|
|
CustomMessage(msg, this, plr);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public func MouseSelection(int plr)
|
|
{
|
|
if(!crew) return false;
|
|
if(plr != GetOwner()) return false;
|
|
|
|
// no object
|
|
if(!myobject) return false;
|
|
|
|
// object is a pushable vehicle
|
|
if(actiontype == ACTIONTYPE_VEHICLE)
|
|
{
|
|
var proc = crew->GetProcedure();
|
|
|
|
// object is inside building -> activate
|
|
if(crew->Contained() && myobject->Contained() == crew->Contained())
|
|
{
|
|
crew->SetCommand("Activate",myobject);
|
|
return true;
|
|
}
|
|
// crew is currently pushing vehicle
|
|
else if(proc == "PUSH")
|
|
{
|
|
// which is mine -> let go
|
|
if(crew->GetActionTarget() == myobject)
|
|
{
|
|
// vehicles might have set their own view and it's not reset on release controls
|
|
// So reset cursor view immediately when ungrabbing
|
|
ResetCursorView(GetController());
|
|
crew->ObjectCommand("UnGrab");
|
|
}
|
|
else
|
|
crew->ObjectCommand("Grab", myobject);
|
|
|
|
return true;
|
|
}
|
|
// grab
|
|
else if(proc == "WALK")
|
|
{
|
|
crew->ObjectCommand("Grab", myobject);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// object is a building
|
|
if(actiontype == ACTIONTYPE_STRUCTURE)
|
|
{
|
|
// inside? -> exit
|
|
if(crew->Contained() == myobject)
|
|
{
|
|
crew->ObjectCommand("Exit");
|
|
return true;
|
|
}
|
|
// outside? -> enter
|
|
else if(crew->CanEnter())
|
|
{
|
|
crew->ObjectCommand("Enter", myobject);
|
|
return true;
|
|
}
|
|
}
|
|
if(actiontype == ACTIONTYPE_SCRIPT)
|
|
{
|
|
if(myobject->~IsInteractable(crew))
|
|
{
|
|
myobject->Interact(crew, modus);
|
|
return true;
|
|
}
|
|
}
|
|
if(actiontype == ACTIONTYPE_EXTRA)
|
|
{
|
|
if(extra)
|
|
extra.Object->Call(extra.Fn, crew);
|
|
}
|
|
}
|
|
|
|
public func OnMouseDragDone(obj, object target)
|
|
{
|
|
// not on landscape
|
|
if(target) return;
|
|
if(GetType(obj) != C4V_C4Object) return;
|
|
if(!crew) return false;
|
|
|
|
var container;
|
|
if(container = obj->Contained())
|
|
{
|
|
if(obj->GetOCF() & OCF_Collectible)
|
|
{
|
|
container->SetCommand("Drop",obj);
|
|
}
|
|
else if(obj->GetOCF() & OCF_Grab)
|
|
{
|
|
if(crew->Contained() == container)
|
|
crew->SetCommand("Activate",obj);
|
|
}
|
|
}
|
|
}
|
|
|
|
public func OnMouseDrag(int plr)
|
|
{
|
|
if(plr != GetOwner()) return false;
|
|
|
|
if(actiontype == ACTIONTYPE_INVENTORY || actiontype == ACTIONTYPE_VEHICLE)
|
|
return myobject;
|
|
|
|
return false;
|
|
}
|
|
|
|
public func OnMouseDrop(int plr, obj)
|
|
{
|
|
if(plr != GetOwner()) return false;
|
|
if(GetType(obj) != C4V_C4Object) return false;
|
|
if(!crew) return false;
|
|
|
|
// anything theoretically can be dropped on script objects
|
|
if(actiontype == ACTIONTYPE_SCRIPT)
|
|
{
|
|
return myobject->~DropObject(obj);
|
|
}
|
|
// a collectible object
|
|
else if(obj->GetOCF() & OCF_Collectible)
|
|
{
|
|
if(actiontype == ACTIONTYPE_INVENTORY)
|
|
{
|
|
var objcontainer = obj->Contained();
|
|
|
|
// object container is the clonk too? Just switch
|
|
if(objcontainer == crew)
|
|
{
|
|
crew->Switch2Items(position, crew->GetItemPos(obj));
|
|
return true;
|
|
}
|
|
|
|
// slot is already full: switch places with other object
|
|
if(myobject != nil)
|
|
{
|
|
var myoldobject = myobject;
|
|
|
|
// 1. exit my object
|
|
myoldobject->Exit();
|
|
// 2. try to enter the other object
|
|
if(crew->Collect(obj,false,position))
|
|
{
|
|
// 3. try to enter my object into other container
|
|
if(!(objcontainer->Collect(myoldobject,true)))
|
|
// -> otherwise, recollect my object
|
|
crew->Collect(myoldobject,false,position);
|
|
}
|
|
// -> otherwise, recollect my object
|
|
else
|
|
crew->Collect(myoldobject,false,position);
|
|
}
|
|
// otherwise, just collect
|
|
else
|
|
{
|
|
crew->Collect(obj,false,position);
|
|
}
|
|
return true;
|
|
}
|
|
else if(actiontype == ACTIONTYPE_VEHICLE)
|
|
{
|
|
if(!myobject) return false;
|
|
// collect if possible
|
|
if(myobject->Collect(obj)) return true;
|
|
// otherwise (lorry is full?): fail
|
|
return false;
|
|
}
|
|
}
|
|
else if(obj->GetOCF() & OCF_Grab)
|
|
{
|
|
if(actiontype == ACTIONTYPE_STRUCTURE)
|
|
{
|
|
// respect no push enter
|
|
if (obj->GetDefCoreVal("NoPushEnter","DefCore")) return false;
|
|
// enter vehicle into structure
|
|
crew->ObjectCommand("PushTo", obj, 0, 0, myobject);
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
public func Disable()
|
|
{
|
|
myobject = nil;
|
|
actiontype = -1;
|
|
hotkey = 0;
|
|
position = 0;
|
|
this["Visibility"] = VIS_None;
|
|
if(subselector)
|
|
subselector->RemoveObject();
|
|
}
|
|
|
|
public func ClearMessage()
|
|
{
|
|
CustomMessage("",this,GetOwner());
|
|
if(subselector)
|
|
CustomMessage("",subselector,GetOwner());
|
|
}
|
|
|
|
public func SetObject(object obj, int type, int pos, int hot, int number, proplist xtra)
|
|
{
|
|
this.Visibility = VIS_Owner;
|
|
|
|
// remove effect that checks whether the object to which this selector
|
|
// refers to is still existant because now this selector gets a new
|
|
// object to which to refer.
|
|
RemoveEffect("IntRemoveGuard",myobject);
|
|
|
|
position = pos;
|
|
actiontype = type;
|
|
myobject = obj;
|
|
hotkey = hot;
|
|
modus = number;
|
|
|
|
// extra stuff
|
|
if(xtra)
|
|
extra = xtra;
|
|
else
|
|
extra = nil;
|
|
|
|
// Set mousedrag for inventory objects
|
|
if (actiontype == ACTIONTYPE_INVENTORY)
|
|
this.MouseDrag = MD_DragSource | MD_DropTarget;
|
|
|
|
if(!myobject)
|
|
{
|
|
SetGraphics("None");
|
|
SetGraphics(nil,nil,1);
|
|
SetName(Format("$TxtSlot$",pos+1));
|
|
this.MouseDragImage = nil;
|
|
if(subselector)
|
|
subselector->RemoveObject();
|
|
}
|
|
else
|
|
{
|
|
SetGraphics("Slot", GUI_ObjectSelector);
|
|
SetGraphics(nil,nil,1,GFXOV_MODE_ObjectPicture, nil, 0, myobject);
|
|
SetName(Format("$TxtSelect$",myobject->GetName()));
|
|
this.MouseDragImage = myobject;
|
|
|
|
// if object has extra slot, show it
|
|
if(myobject->~HasExtraSlot())
|
|
{
|
|
if(!subselector)
|
|
{
|
|
subselector = CreateObjectAbove(GUI_ExtraSlot,0,0,GetOwner());
|
|
subselector->SetPosition(GetX()+24,GetY()+24);
|
|
}
|
|
subselector->SetContainer(myobject);
|
|
subselector->SetCrew(crew);
|
|
}
|
|
// or otherwise, remove it
|
|
else if(subselector)
|
|
{
|
|
subselector->RemoveObject();
|
|
}
|
|
|
|
// create an effect which monitors whether the object is removed:
|
|
// this is only necessary for inventory as all the other slots
|
|
// are checked via the effect
|
|
if(actiontype == ACTIONTYPE_INVENTORY)
|
|
{
|
|
AddEffect("IntRemoveGuard",myobject,1,0,this);
|
|
}
|
|
}
|
|
|
|
ShowHotkey();
|
|
UpdateSelectionStatus();
|
|
}
|
|
|
|
public func ShowSelector() { this["Visibility"] = VIS_Owner; }
|
|
public func HideSelector() { this["Visibility"] = VIS_None; }
|
|
|
|
|
|
public func FxIntRemoveGuardStop(object target, effect, int reason, bool temp)
|
|
{
|
|
if(reason == 3)
|
|
if(target == myobject)
|
|
SetObject(nil,0,position);
|
|
}
|
|
|
|
public func SetCrew(object c)
|
|
{
|
|
if(crew == c) return;
|
|
|
|
crew = c;
|
|
SetOwner(c->GetOwner());
|
|
|
|
this["Visibility"] = VIS_Owner;
|
|
}
|
|
|
|
public func GetCrew() { return crew; }
|
|
|
|
public func ShowHotkey()
|
|
{
|
|
if(hotkey > 10 || hotkey <= 0)
|
|
{
|
|
SetGraphics(nil,nil,12);
|
|
}
|
|
else
|
|
{
|
|
var num = hotkey;
|
|
if(hotkey == 10) num = 0;
|
|
var name = Format("%d",num);
|
|
SetGraphics(name,Icon_Number,12,GFXOV_MODE_IngamePicture);
|
|
SetObjDrawTransform(300,0,14500,0,300,-32000, 12);
|
|
SetClrModulation(RGB(255,230,180),12);
|
|
}
|
|
}
|
|
|
|
public func Selected()
|
|
{
|
|
return selected;
|
|
}
|
|
|
|
public func UpdateSelectionStatus()
|
|
{
|
|
if(!crew) return;
|
|
|
|
// determine...
|
|
var sel = 0;
|
|
|
|
if(actiontype == ACTIONTYPE_EXTRA)
|
|
{
|
|
if(extra)
|
|
{
|
|
SetGraphics(extra.IconName,extra.IconID,2,GFXOV_MODE_IngamePicture);
|
|
this.Tooltip = extra.Description;
|
|
}
|
|
}
|
|
|
|
// script...
|
|
else if(actiontype == ACTIONTYPE_SCRIPT)
|
|
{
|
|
this.Tooltip = nil;
|
|
var metainfo = myobject->~GetInteractionMetaInfo(crew, modus);
|
|
if(metainfo)
|
|
{
|
|
SetGraphics(metainfo["IconName"],metainfo["IconID"],2,GFXOV_MODE_IngamePicture);
|
|
SetObjDrawTransform(IconSize(),0,-16000,0,IconSize(),20000, 2);
|
|
|
|
var desc = metainfo["Description"];
|
|
if(desc)
|
|
this.Tooltip = desc;
|
|
|
|
if(metainfo["Selected"])
|
|
SetObjDrawTransform(1200,0,0,0,1200,0,1);
|
|
}
|
|
|
|
return;
|
|
}
|
|
else if(actiontype == ACTIONTYPE_VEHICLE)
|
|
{
|
|
if(crew->GetProcedure() == "PUSH" && crew->GetActionTarget() == myobject)
|
|
sel = 1;
|
|
}
|
|
else if(actiontype == ACTIONTYPE_STRUCTURE)
|
|
{
|
|
if(crew->Contained() == myobject)
|
|
sel = 1;
|
|
}
|
|
else if(actiontype == ACTIONTYPE_INVENTORY)
|
|
{
|
|
if(0 == position)
|
|
sel += 1;
|
|
if(1 == position)
|
|
sel += 2;
|
|
}
|
|
selected = sel;
|
|
|
|
// and set the icon...
|
|
if(selected)
|
|
{
|
|
//SetClrModulation(RGB(220,0,0),12);
|
|
//SetObjDrawTransform(500,0,16000,0,500,-34000, 12);
|
|
if(myobject) {
|
|
SetObjDrawTransform(1200,0,0,0,1200,0,1);
|
|
}
|
|
|
|
if(actiontype == ACTIONTYPE_VEHICLE)
|
|
{
|
|
SetGraphics("LetGo",GetID(),2,GFXOV_MODE_Base);
|
|
this.Tooltip = Format("$TxtUnGrab$",myobject->GetName());
|
|
}
|
|
else if(actiontype == ACTIONTYPE_STRUCTURE)
|
|
{
|
|
SetGraphics("Exit",GetID(),2,GFXOV_MODE_Base);
|
|
this.Tooltip = Format("$TxtExit$",myobject->GetName());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//SetClrModulation(RGB(160,0,0),12);
|
|
//SetObjDrawTransform(300,0,16000,0,300,-34000, 12);
|
|
if(myobject) {
|
|
SetObjDrawTransform(900,0,0,0,900,0,1);
|
|
}
|
|
|
|
if(actiontype == ACTIONTYPE_VEHICLE)
|
|
{
|
|
if(!(myobject->Contained()))
|
|
{
|
|
SetGraphics("Grab",GetID(),2,GFXOV_MODE_Base);
|
|
this.Tooltip = Format("$TxtGrab$",myobject->GetName());
|
|
}
|
|
else
|
|
{
|
|
SetGraphics("Exit",GetID(),2,GFXOV_MODE_Base);
|
|
this.Tooltip = Format("$TxtPushOut$",myobject->GetName());
|
|
}
|
|
}
|
|
if(actiontype == ACTIONTYPE_STRUCTURE)
|
|
{
|
|
SetGraphics("Enter",GetID(),2,GFXOV_MODE_Base);
|
|
this.Tooltip = Format("$TxtEnter$",myobject->GetName());
|
|
}
|
|
}
|
|
SetObjDrawTransform(IconSize(),0,-16000,0,IconSize(),20000, 2);
|
|
}
|