openclonk/planet/Defense.ocf/Defense.ocd/Homebase.ocd/BuyMenu.ocd/Script.c

285 lines
7.4 KiB
C

/**
Buy Menu
Shows icons to instantly buy+equip weapons
@authors Sven2
*/
local container, container_id; // container window containing menu entries and other stuff
local menu; // the actual menu (a MenuStyle_Grid)
local description_box, description_name_id, description_desc_id, description_message_id; // box showing name+desc of currently hovered item
local homebase; // associated base
local buymenu_toggle_id; // button to toggle menu visibility
local hovered_entry_index; // keep track of hovered entry to update description box
/* Creation / Destruction */
public func Construction(...)
{
// The menu. Cannot inherit from MenuStyle_Grid, because at the moment the menu host
// is the object itself. Therefore, child elements such as the buy menu would become
// invisible if the menu closes. So just create an extra object for now.
menu = CreateObject(MenuStyle_Grid, 0,0, GetOwner());
menu->SetPermanent(true);
menu->SetMouseOverCallback(this, "OnMenuEntryHover");
menu->SetMouseOutCallback(this, "OnMenuEntryHoverExit");
menu.Player = nil; // by visibility
menu.Bottom = "100% - 5em";
menu.BackgroundColor = 0x20000000;
menu.Visibility = VIS_None;
// Create description box
description_box =
{
Top = menu.Bottom,
Margin = ["0em", "0em"],
BackgroundColor = 0x40000000,
Target = this,
ID = 0xffffef,
name_part =
{
Bottom = "1em",
Left = "0.2em",
ID = description_name_id = 3,
Target = this
},
desc_part =
{
Top = "1em",
Bottom = "3em",
ID = description_desc_id = 4,
Target = this,
},
message_part =
{
Top = "3em",
Bottom = "5em",
ID = description_message_id = 5,
Target = this,
}
};
// overall container
container =
{
Left = "100% - 14em",
Top = "4em",
Right = "100% - 1em",
Bottom = "100% - 4em",
Style = GUI_Multiple,
Target = menu, // bind visibility to menu object
ID = 0xffffee,
menu = menu,
description_box = description_box
};
// Create button to show/hide menu
CreateToggleVisibilityButton();
return true;
}
public func Destruction(...)
{
if (container_id) GuiClose(container_id);
if (menu) menu->RemoveObect();
DestroyToggleVisibilityButton();
return true;
}
public func SetHomebase(object to)
{
homebase = [to];
return true;
}
// Forward menu operations
public func Open()
{
if (container_id) GuiClose(container_id);
container_id = GuiOpen(container);
hovered_entry_index = -1;
return false;
}
public func RemoveItem(idx)
{
OnMenuEntryHoverExit(idx, idx, GetOwner()); // remove description
if (menu) return menu->RemoveItem(idx, container_id);
return false;
}
/* Buy menu entries */
public func UpdateCaption(string title, bool available, proplist entry, int item_idx)
{
if (!menu) return false;
var custom_entry = { Bottom = "+1.3em" }, fontclr, bgclr, bgclr_hover;
if (available)
{
fontclr = 0xffffff;
bgclr = nil;
}
else
{
fontclr = 0x7f7f7f;
bgclr = 0x50000000;
}
custom_entry.BackgroundColor = bgclr;
custom_entry.Text = Format(" <c %x>%s</c>", fontclr, title);
custom_entry.Style = GUI_IgnoreMouse | GUI_TextBottom;
menu->AddItem(GetID(), nil, item_idx, this, this.ClickCaption, item_idx, custom_entry, container_id, true);
return true;
}
public func ClickCaption() { return true; } // nothing to be done here (maybe expand/collapse in the future)
public func UpdateBuyEntry(id buy_def, bool available, proplist entry, int callback_idx, bool was_last_selection)
{
if (!menu) return false;
var custom_entry = {Bottom = "+2em", Right = Format("+%dem", 2+entry.extra_width), Symbol = buy_def, GraphicsName=entry.graphic }, fontclr, bgclr, bgclr_hover;
if (available)
{
fontclr = 0x00ff00;
bgclr = 0x507f7f7f;
bgclr_hover = 0x507fff7f;
}
else
{
fontclr = 0x7f7f7f;
bgclr = 0x50000000;
bgclr_hover = 0x50ff0000;
}
if (entry.cost)
{
custom_entry.price = {
Text = Format("{{Icon_Wealth}}<c %x>%d</c>", fontclr, entry.cost),
Style = GUI_TextRight | GUI_TextBottom
};
custom_entry.Style = GUI_FitChildren;
}
if (entry.hotkey)
{
custom_entry.hotkey = {
Text = Format("<c %x>[%s]</c>", 0xffff00, entry.hotkey),
Style = GUI_TextRight | GUI_TextTop
};
}
if (was_last_selection)
{
custom_entry.selection_marker = {
Top = "100% - 2em", Right = "+50%", Symbol = Icon_Ok
};
}
custom_entry.BackgroundColor = {Std = bgclr, OnHover = bgclr_hover };
menu->AddItem(buy_def, nil, callback_idx, this, this.ClickBuyButton, callback_idx, custom_entry, container_id, true);
return true;
}
public func ClickBuyButton(int callback_idx, entry_id, int player)
{
if (homebase && homebase[0])
{
if (player != homebase[0]->GetOwner()) return false; // wat?
if (homebase[0]->OnBuySelection(callback_idx)) return true;
Sound("Hits::Materials::Metal::DullMetalHit3", true, nil, player);
}
return false;
}
public func OnMenuEntryHover(int entry_idx, int entry_id, int player)
{
if (homebase && homebase[0])
{
if (player != homebase[0]->GetOwner()) return false; // wat?
var info = homebase[0]->GetEntryInformation(entry_idx);
if (!info) info = {}; // clear boxes on invalid
GuiUpdateText(Format("<c ffff00>%s</c>", info.name ?? ""), container_id, description_name_id, this);
GuiUpdateText(info.desc ?? "", container_id, description_desc_id, this);
GuiUpdateText(info.message ?? "", container_id, description_message_id, this);
hovered_entry_index = entry_idx;
return true;
}
return false;
}
public func OnMenuEntryHoverExit(int entry_idx, int entry_id, int player)
{
if (homebase && homebase[0])
{
if (player != homebase[0]->GetOwner()) return false; // wat?
if (hovered_entry_index == entry_idx) // must check for index because next Hover callback might have arrived before HoverExit callback
{
GuiUpdateText("", container_id, description_name_id, this);
GuiUpdateText("", container_id, description_desc_id, this);
GuiUpdateText("", container_id, description_message_id, this);
}
return true;
}
return false;
}
/* Buy menu open/close button */
private func CreateToggleVisibilityButton()
{
var plr = GetOwner();
var hotkey_string = GetPlayerControlAssignment(GetOwner(), CON_ToggleShop, true);
if (hotkey_string && GetLength(hotkey_string) > 0)
hotkey_string = Format("|<c ffff00>[%s]</c>", hotkey_string);
else
hotkey_string = "";
var buymenu_button_menu =
{
Target = this,
Player = plr,
Style = GUI_Multiple | GUI_TextHCenter | GUI_TextBottom,
// Place the button just left of the wealth display
Left = "100% - 9em",
Right = "100% - 6.5em",
Top = "0.5em",
Bottom = "3em",
Priority = 1, // Z order?
// Hover child element because a root window cannot collect clicks properly
hover = {
OnMouseIn = GuiAction_SetTag("OnHover"),
OnMouseOut = GuiAction_SetTag("Std"),
OnClick = GuiAction_Call(this, "ToggleVisibility"),
BackgroundColor = {Std = nil, OnHover = 0x50000000 },
//GraphicsName = GetGraphicsName(is_open),
Symbol = { Std=Library_Base, OnHover=Library_Base },
Text = { Std=Format("$Buy$%s", hotkey_string), OnHover=Format("<c ffff00>$Buy$</c>%s", hotkey_string) },
}
};
buymenu_toggle_id = GuiOpen(buymenu_button_menu);
return true;
}
private func DestroyToggleVisibilityButton()
{
GuiClose(buymenu_toggle_id);
return true;
}
public func ToggleVisibility(int player, ...)
{
if (!menu) return false;
if (menu.Visibility == VIS_Owner)
{
// Close menu
menu.Visibility = VIS_None;
Sound("GUI_BuyMenu::CloseBuyMenu", true, nil, GetOwner());
}
else
{
// Open menu
menu.Visibility = VIS_Owner;
Sound("GUI_BuyMenu::OpenBuyMenu", true, nil, GetOwner());
}
return true;
}