218 lines
34 KiB
C++
218 lines
34 KiB
C++
#include "IronsGame.h"
|
||
#include "IronsPerformanceOverlay.h"
|
||
#include "Blueprint/WidgetTree.h"
|
||
#include "Components/CanvasPanel.h"
|
||
#include "Components/StaticMeshComponent.h"
|
||
#include "Rendering/DrawElements.h"
|
||
#include "Styling/CoreStyle.h"
|
||
#include "Framework/Application/SlateApplication.h"
|
||
#include "Fonts/FontMeasure.h"
|
||
#include "Fonts/CompositeFont.h"
|
||
#include "Engine/Texture2D.h"
|
||
#include "GameFramework/GameUserSettings.h"
|
||
#include "Kismet/KismetSystemLibrary.h"
|
||
#include "Misc/Paths.h"
|
||
#include "EngineUtils.h"
|
||
|
||
namespace {
|
||
FString W(std::string_view S){return FString(UTF8_TO_TCHAR(std::string(S).c_str()));}
|
||
std::string U(const FString& S){return std::string(TCHAR_TO_UTF8(*S));}
|
||
const FLinearColor Ink(.79f,.87f,.9f),Muted(.39f,.5f,.56f),Teal(.28f,.82f,.8f),Amber(.96f,.68f,.26f),Panel(.025f,.041f,.052f,.94f),Line(.13f,.23f,.28f,.9f);
|
||
struct FPainter {
|
||
const FGeometry& G;FSlateWindowElementList& Out;int Layer;float Scale;FVector2D Origin;FString FontPath;
|
||
FPainter(const FGeometry& Geo,FSlateWindowElementList& O,int L,const UIronsGameInstance* H):G(Geo),Out(O),Layer(L){auto Layout=FIronsPerformanceLayout::Make(G.GetLocalSize(),H&&H->bShowPerformance,H?H->PerformanceCorner:0);Scale=Layout.ContentScale;Origin=Layout.ContentOrigin;FontPath=FPaths::ProjectContentDir()/TEXT("IRONSPORE/Raw/Fonts/IronsSansSC-Regular.ttf");}
|
||
FPaintGeometry Geo(float X,float Y,float Width,float Height)const{return G.ToPaintGeometry(FVector2D(Width,Height)*Scale,FSlateLayoutTransform(FVector2D(X,Y)*Scale+Origin));}
|
||
void Rect(float X,float Y,float Width,float Height,FLinearColor C){FSlateDrawElement::MakeBox(Out,Layer++,Geo(X,Y,Width,Height),FCoreStyle::Get().GetBrush(TEXT("WhiteBrush")),ESlateDrawEffect::None,C);}
|
||
void Frame(float X,float Y,float Width,float Height,FLinearColor C=Line){Rect(X,Y,Width,1,C);Rect(X,Y+Height-1,Width,1,C);Rect(X,Y,1,Height,C);Rect(X+Width-1,Y,1,Height,C);}
|
||
void Text(float X,float Y,const FString& String,float Size=20,FLinearColor C=Ink,float MaxWidth=0){
|
||
static TSharedPtr<const FCompositeFont> Composite=MakeShared<FCompositeFont>(TEXT("Regular"),FontPath,EFontHinting::Default,EFontLoadingPolicy::LazyLoad);
|
||
FSlateFontInfo Font(Composite,Size*Scale,TEXT("Regular"));FString S=String;
|
||
if(MaxWidth>0){auto Measure=FSlateApplication::Get().GetRenderer()->GetFontMeasureService();while(S.Len()>1&&Measure->Measure(S,Font).X>MaxWidth*Scale)S.LeftChopInline(1);if(S!=String&&S.Len()>2)S=S.LeftChop(2)+TEXT("…");}
|
||
FSlateDrawElement::MakeText(Out,Layer++,Geo(X,Y,1,1),S,Font,ESlateDrawEffect::None,C);
|
||
}
|
||
void Image(float X,float Y,float Width,float Height,UTexture2D* Texture,FLinearColor Tint=FLinearColor::White){if(!Texture)return;FSlateBrush Brush;Brush.SetResourceObject(Texture);Brush.ImageSize=FVector2D(Texture->GetSizeX(),Texture->GetSizeY());Brush.DrawAs=ESlateBrushDrawType::Image;float Ratio=FMath::Min(Width/Texture->GetSizeX(),Height/Texture->GetSizeY());FVector2D D(Texture->GetSizeX()*Ratio,Texture->GetSizeY()*Ratio);FSlateDrawElement::MakeBox(Out,Layer++,Geo(X+(Width-D.X)*.5f,Y+(Height-D.Y)*.5f,D.X,D.Y),&Brush,ESlateDrawEffect::None,Tint);}
|
||
};
|
||
}
|
||
AIronsController* UIronsScreen::Controller()const{return Cast<AIronsController>(GetOwningPlayer());}
|
||
UIronsGameInstance* UIronsScreen::Host()const{return Cast<UIronsGameInstance>(GetGameInstance());}
|
||
void UIronsScreen::NativeConstruct(){Super::NativeConstruct();SetIsFocusable(true);SetVisibility(ESlateVisibility::Visible);if(!WidgetTree->RootWidget)WidgetTree->RootWidget=WidgetTree->ConstructWidget<UCanvasPanel>();WidgetTree->RootWidget->SetVisibility(ESlateVisibility::Visible);
|
||
for(const auto& E:gf::Catalog::defaults().equipment){FString Id=W(E.id);Icons.Add(Id,LoadObject<UTexture2D>(nullptr,*(TEXT("/Game/IRONSPORE/UI/Icons/T_")+Id+TEXT(".T_")+Id)));}
|
||
Icons.Add(TEXT("silhouette"),LoadObject<UTexture2D>(nullptr,TEXT("/Game/IRONSPORE/UI/Icons/T_MechFrontSilhouette.T_MechFrontSilhouette")));
|
||
}
|
||
void UIronsScreen::ClearSelection(){Selected.Empty();DragUid.Empty();bDragging=false;SelectedSlot=-1;Scroll=0;}
|
||
std::vector<std::string> UIronsScreen::SelectedPodItems()const{std::vector<std::string> V;for(const auto& S:PodSelection)V.push_back(U(S));return V;}
|
||
int32 UIronsScreen::NativePaint(const FPaintArgs& Args,const FGeometry& G,const FSlateRect& Cull,FSlateWindowElementList& Out,int32 Layer,const FWidgetStyle& Style,bool Enabled)const{
|
||
int32 Base=Super::NativePaint(Args,G,Cull,Out,Layer,Style,Enabled);auto H=Host();auto C=Controller();if(!H||!C)return Base;
|
||
Hits.Empty();Grids.Empty();FPainter P(G,Out,Base+1,H);auto L=[&](const TCHAR* Key){return H->Label(Key);};auto& S=H->Core();const auto& State=S.state();const auto& Run=State.run;
|
||
auto Hit=[&](float X,float Y,float Width,float Height,FString Cmd,FString Arg=TEXT(""),int A=0,int B=0,int D=0){Hits.Add({FSlateRect(X,Y,X+Width,Y+Height),MoveTemp(Cmd),MoveTemp(Arg),A,B,D});};
|
||
auto Button=[&](float X,float Y,float Width,float Height,const FString& Text,const FString& Cmd,const FString& Arg=TEXT(""),int A=0,bool Active=false){bool Hover=FSlateRect(X,Y,X+Width,Y+Height).ContainsPoint(Pointer);P.Rect(X,Y,Width,Height,Active?FLinearColor(.08f,.27f,.29f,.98f):Hover?FLinearColor(.10f,.17f,.21f,.98f):Panel);P.Frame(X,Y,Width,Height,Active?Teal:Line);P.Rect(X,Y,3,Height,Active||Hover?Teal:Muted);P.Text(X+16,Y+Height*.5f-15,Text,20,Active?Teal:Ink,Width-30);Hit(X,Y,Width,Height,Cmd,Arg,A);};
|
||
auto Section=[&](float X,float Y,float Width,float Height,const FString& Title,const FString& Sub){P.Rect(X,Y,Width,Height,Panel);P.Frame(X,Y,Width,Height);P.Rect(X,Y,Width,3,Teal*.7f);P.Text(X+22,Y+17,Title,25);P.Text(X+22,Y+56,Sub,15,Muted,Width-35);P.Rect(X+20,Y+91,Width-40,1,Line);};
|
||
auto DrawItem=[&](float X,float Y,float Width,float Height,const gf::Item& I,gf::Hold Hold,bool Reserved=false){
|
||
FString Id=W(I.itemId),Uid=W(I.uid);bool Sel=Selected==Uid,Pod=PodSelection.Contains(Uid);P.Rect(X+2,Y+2,Width-4,Height-4,Sel?FLinearColor(.09f,.28f,.31f):FLinearColor(.065f,.105f,.13f));P.Frame(X+2,Y+2,Width-4,Height-4,Pod?Amber:Sel?Teal:Line);
|
||
if(const auto* T=Icons.Find(Id);T&&*T)P.Image(X+7,Y+12,Width-14,Height-27,*T);else{P.Text(X+5,Y+Height*.35f-4,Id==TEXT("alloy")?TEXT("Fe"):Id==TEXT("cells")?TEXT("+"):TEXT("BP"),Width<70?16:24,Teal,Width-10);}
|
||
if(Width>=70&&Height>=70)P.Text(X+7,Y+4,H->ItemName(I.itemId),12,Ink,Width-13);if(I.count>1)P.Text(X+Width-23,Y+Height-19,FString::FromInt(I.count),12,Teal);
|
||
if(Reserved)P.Text(X+7,Y+Height-23,L(TEXT("hangar.reserved")),11,Amber,Width-10);if(I.borrowed)P.Text(X+7,Y+Height-23,L(TEXT("ue.borrowed")),11,Amber,Width-10);
|
||
Hit(X,Y,Width,Height,TEXT("item"),Uid,static_cast<int>(Hold));
|
||
};
|
||
auto Grid=[&](float X,float Y,int Width,int Height,float Cell,gf::Hold Hold,const std::vector<gf::Item>& Items,int StartRow=0,int VisibleRows=0){
|
||
int Rows=VisibleRows?VisibleRows:Height;P.Rect(X,Y,Width*Cell,Rows*Cell,FLinearColor(.018f,.03f,.039f));for(int I=0;I<=Width;I++)P.Rect(X+I*Cell,Y,1,Rows*Cell,Line);for(int I=0;I<=Rows;I++)P.Rect(X,Y+I*Cell,Width*Cell,1,Line);
|
||
Grids.Add({FSlateRect(X,Y,X+Width*Cell,Y+Rows*Cell),Hold,Cell,Width,Height});
|
||
Out.PushClip(FSlateClippingZone(P.Geo(X,Y,Width*Cell,Rows*Cell)));
|
||
for(const auto& I:Items){auto Size=gf::Grid::size(I.itemId,I.rotated);if(I.y+Size.second<=StartRow||I.y>=StartRow+Rows)continue;DrawItem(X+I.x*Cell,Y+(I.y-StartRow)*Cell,Size.first*Cell,Size.second*Cell,I,Hold,Hold==gf::Hold::Warehouse&&!Run.active&&S.reserved(I.uid));}
|
||
Out.PopClip();
|
||
};
|
||
bool Play=C->Playing();FString Page=C->Page;
|
||
if(!Play){P.Rect(0,0,1920,1080,FLinearColor(.005f,.015f,.025f,Page==TEXT("home")?.18f:.7f));P.Rect(0,0,1920,112,FLinearColor(.015f,.026f,.035f,.93f));P.Rect(40,110,1840,1,Line);P.Text(56,28,TEXT("IRONSPORE"),35);P.Text(320,44,TEXT("// ")+L(TEXT("ue.subtitle")),16,Muted);P.Text(1440,28,FString::Printf(TEXT("%s %03d / %s %03d"),*L(TEXT("ue.sorties")),State.sorties,*L(TEXT("ue.returns")),State.extractions),16,Teal,430);P.Text(1440,62,Run.active?L(TEXT("ue.activeRun")):L(TEXT("ue.standby")),14,Muted);}
|
||
if(Page==TEXT("home")){
|
||
P.Rect(40,150,480,770,FLinearColor(.02f,.034f,.046f,.82f));P.Text(75,176,L(TEXT("ue.baseTitle")),32);P.Text(78,225,TEXT("01 / OPERATIONS"),15,Teal);
|
||
Button(76,282,405,65,L(TEXT("ue.enterHangar")),TEXT("page"),TEXT("hangar"),0,true);
|
||
Button(76,365,405,65,L(Run.active?TEXT("ue.resume"):TEXT("ue.deploy")),TEXT("launch"));
|
||
Button(76,448,405,65,L(TEXT("ue.training")),TEXT("training"));Button(76,531,405,65,L(TEXT("ue.research")),TEXT("page"),TEXT("research"));Button(76,614,405,65,L(TEXT("ue.settings")),TEXT("page"),TEXT("settings"));Button(76,697,405,65,L(TEXT("ue.quit")),TEXT("quit"));
|
||
P.Text(78,832,L(TEXT("ue.baseHint")),16,Muted,405);
|
||
Section(1470,168,410,390,L(TEXT("ue.pilot")),TEXT("RCI / IRON-01"));P.Text(1494,282,L(TEXT("ue.warehouse")),18,Muted);P.Text(1494,321,FString::Printf(TEXT("%d / %d"),gf::Grid::occupied(State.warehouse),State.warehouseWidth*State.warehouseHeight),37,Teal);P.Text(1494,391,L(TEXT("ue.pending")),17,Muted);P.Text(1494,428,FString::FromInt(State.recoveryInbox.size()),34,State.recoveryInbox.empty()?Ink:Amber);P.Text(1494,500,L(TEXT("ue.completed"))+TEXT(" ")+FString::FromInt(State.completed),14,Muted);
|
||
}else if(Page==TEXT("hangar")||Page==TEXT("inventory")){
|
||
bool Field=Page==TEXT("inventory");Section(40,135,520,790,L(TEXT("hangar.equipment")),L(Field?TEXT("ue.fieldEquipment"):Run.active?TEXT("hangar.readOnly"):TEXT("hangar.draft")));Section(580,135,500,790,L(TEXT("hangar.carry")),L(TEXT("ue.carryHint")));Section(1100,135,780,790,L(Field?TEXT("ue.fieldSystems"):TEXT("ue.warehouse")),L(Field?TEXT("ue.fieldHint"):TEXT("ue.warehouseHint")));
|
||
if(const auto* T=Icons.Find(TEXT("silhouette"));T&&*T)P.Image(175,250,250,450,*T,FLinearColor(.35f,.47f,.55f,.4f));
|
||
auto Parts=Run.active?Run.equipment:S.draft().equipment;int Chassis=Run.active?Run.chassis:S.draft().chassis;
|
||
for(int SlotIndex=0;SlotIndex<4;SlotIndex++){float X=SlotIndex%2?351:63,Y=245+(SlotIndex/2)*230;auto E=S.catalog().part(SlotIndex,Parts[SlotIndex]);gf::Item Item;Item.itemId=E?E->id:"";Item.uid="slot"+std::to_string(SlotIndex);if(Run.active)for(const auto& I:Run.installed)if(gf::Grid::slot(I.itemId)==SlotIndex)Item=I;
|
||
P.Rect(X,Y,184,200,FLinearColor(.03f,.065f,.08f,.8f));P.Frame(X,Y,184,200,SelectedSlot==SlotIndex?Teal:Line);if(E){if(const auto* T=Icons.Find(W(E->id));T&&*T)P.Image(X+20,Y+25,144,115,*T);P.Text(X+10,Y+151,H->ItemName(E->id),16,Ink,164);}else P.Text(X+20,Y+90,L(TEXT("hangar.emptySlot")),17,Muted);
|
||
FString SlotKey=SlotIndex==0?TEXT("ue.primary"):SlotIndex==1?TEXT("ue.secondary"):SlotIndex==2?TEXT("ue.booster"):TEXT("ue.guard");P.Text(X+8,Y+5,H->Label(SlotKey),13,Muted);Hit(X,Y,184,200,TEXT("slot"),TEXT(""),SlotIndex);}
|
||
P.Text(65,714,H->Label(FString::Printf(TEXT("chassis.chassis_%d.name"),Chassis)),23,Teal);float Mass=0,Power=0;for(int SlotIndex=0;SlotIndex<4;SlotIndex++)if(auto E=S.catalog().part(SlotIndex,Parts[SlotIndex])){Mass+=E->mass;Power+=E->power;}const auto& Ch=S.catalog().chassis[Chassis];P.Text(65,757,FString::Printf(TEXT("%s %.0f / %.0f %s %.0f / %.0f"),*L(TEXT("ue.mass")),Mass,Ch.massCapacity,*L(TEXT("ue.power")),Power,Ch.powerCapacity),17,S.catalog().fits(Chassis,Parts)?Ink:Amber,460);
|
||
for(int I=0;I<3;I++)Button(65+I*157,817,146,55,H->Label(FString::Printf(TEXT("chassis.chassis_%d.name"),I)),TEXT("chassis"),TEXT(""),I,Chassis==I);
|
||
std::vector<gf::Item> Cargo=Run.cargo,Safe=Run.safeCase;if(!Run.active){Cargo.clear();Safe.clear();for(const auto& I:S.draft().items)if(auto Item=gf::find(State.warehouse,I.uid)){auto Copy=*Item;Copy.count=I.count;Copy.x=I.x;Copy.y=I.y;Copy.rotated=I.rotated;(I.hold==gf::Hold::Cargo?Cargo:Safe).push_back(Copy);}}
|
||
P.Text(612,245,L(TEXT("ue.cargo"))+TEXT(" 4 × 4"),18,Muted);Grid(612,283,4,4,101,gf::Hold::Cargo,Cargo);P.Text(612,710,L(TEXT("ue.safeCase")),18,Teal);Grid(612,746,2,2,64,gf::Hold::SafeCase,Safe);P.Text(763,753,L(TEXT("hangar.protected")),14,Muted,290);Button(765,807,266,53,L(TEXT("hangar.details")),TEXT("details"));
|
||
if(!Field){P.Text(1125,244,FString::Printf(TEXT("10 × 24 / %d %s"),gf::Grid::occupied(State.warehouse),*L(TEXT("ue.cellsUsed"))),15,Muted);Grid(1125,282,10,24,44,gf::Hold::Warehouse,State.warehouse,Scroll,12);Button(1125,837,110,43,TEXT("↑"),TEXT("scroll"),TEXT(""),-4);Button(1245,837,110,43,TEXT("↓"),TEXT("scroll"),TEXT(""),4);Button(1365,837,198,43,L(TEXT("ue.sort")),TEXT("sort"));P.Text(1125,890,FString::Printf(TEXT("%02d–%02d / 24"),Scroll+1,Scroll+12),14,Muted);}
|
||
float DX=Field?1125:1590,DW=Field?710:266;float DY=Field?245:245;
|
||
if(Field){Button(DX,DY,DW,55,L(TEXT("ue.podSelect")),TEXT("podMode"),TEXT(""),0,bPodSelect);P.Text(DX,DY+77,L(TEXT("ue.podRule")),16,Amber,DW);P.Text(DX,DY+110,L(TEXT("ue.holdPod"))+TEXT(" [")+H->Keys[11]+TEXT("]"),19,Teal,DW);P.Text(DX,DY+160,FString::Printf(TEXT("%s: %d / 4"),*L(TEXT("ue.selected")),PodSelection.Num()),19);DY+=220;}
|
||
if(bDetails){const gf::Item* Item=nullptr;if(SelectedHold==gf::Hold::Warehouse)Item=gf::find(State.warehouse,U(Selected));else if(Run.active)Item=gf::find(SelectedHold==gf::Hold::Cargo?Cargo:Safe,U(Selected));else Item=gf::find(State.warehouse,U(Selected));
|
||
if(SelectedSlot>=0){int SlotIndex=SelectedSlot;auto E=S.catalog().part(SlotIndex,Parts[SlotIndex]);P.Text(DX,DY,E?H->ItemName(E->id):L(TEXT("hangar.emptySlot")),20,Teal,DW);if(Field)Button(DX,DY+55,DW,48,L(TEXT("ue.uninstall")),TEXT("uninstall"),TEXT(""),SlotIndex);else if(!Run.active)Button(DX,DY+55,DW,48,L(TEXT("ue.borrow")),TEXT("borrow"),TEXT(""),SlotIndex);}
|
||
else if(Item){P.Text(DX,DY,H->ItemName(Item->itemId),20,Teal,DW);P.Text(DX,DY+35,TEXT("UID ")+W(Item->uid).Left(10),12,Muted,DW);P.Text(DX,DY+64,FString::Printf(TEXT("%s %d / %d"),*L(TEXT("warehouse.quantity")),Quantity,Item->count),17);Button(DX,DY+100,55,40,TEXT("−"),TEXT("quantity"),TEXT(""),-1);Button(DX+65,DY+100,55,40,TEXT("+"),TEXT("quantity"),TEXT(""),1);float AY=DY+155;
|
||
if(!Run.active){if(gf::Grid::slot(Item->itemId)>=0){Button(DX,AY,DW,44,L(TEXT("ue.equip")),TEXT("equip"));AY+=54;}Button(DX,AY,DW,44,L(TEXT("ue.toCargo")),TEXT("prepare"),TEXT(""),0);AY+=54;Button(DX,AY,DW,44,L(TEXT("ue.toSafe")),TEXT("prepare"),TEXT(""),1);AY+=54;Button(DX,AY,DW,44,L(TEXT("ue.unprepare")),TEXT("unprepare"));AY+=54;}
|
||
else{if(gf::Grid::slot(Item->itemId)>=0){Button(DX,AY,DW,44,L(TEXT("ue.install")),TEXT("install"));AY+=54;}Button(DX,AY,DW,44,L(TEXT("ue.transfer")),TEXT("transfer"));AY+=54;}
|
||
if(!Run.active&&gf::Grid::blueprint(Item->itemId)){Button(DX,AY,DW,44,L(TEXT("ue.research")),TEXT("research"),W(Item->itemId));AY+=54;Button(DX,AY,DW,44,L(TEXT("ue.recycle")),TEXT("recycle"));}
|
||
P.Text(DX,880,L(TEXT("ue.dragHint")),13,Muted,DW);
|
||
}else{P.Text(DX,DY,L(TEXT("ue.selectItem")),18,Muted,DW);P.Text(DX,DY+45,L(TEXT("ue.dragHint")),14,Muted,DW);}
|
||
}
|
||
if(!Field&&State.recoveryInbox.size()>0){Button(1125,938,438,50,L(TEXT("ue.pending"))+TEXT(" ")+FString::FromInt(State.recoveryInbox.size()),TEXT("page"),TEXT("inbox"),0,true);}
|
||
Button(40,950,220,55,L(Field?TEXT("ue.resume"):TEXT("ue.back")),TEXT("page"),Field?TEXT("play"):TEXT("home"));if(!Field)Button(765,950,315,55,L(Run.active?TEXT("ue.resume"):TEXT("ue.deploy")),TEXT("launch"),TEXT(""),0,true);
|
||
}else if(Page==TEXT("research")){
|
||
Section(90,160,1740,720,L(TEXT("ue.research")),L(TEXT("ue.researchHint")));int I=0;for(const auto* Id:{"blueprint_coil_capacitor","blueprint_boost_efficient","blueprint_reactive_guard"}){auto R=gf::Grid::recipe(Id);bool Unlocked=std::find(State.unlocked.begin(),State.unlocked.end(),std::string(Id))!=State.unlocked.end();float X=130+I*565;P.Rect(X,300,525,470,FLinearColor(.04f,.08f,.10f));P.Frame(X,300,525,470);P.Text(X+20,330,H->ItemName(Id),25,Teal,485);if(auto T=Icons.Find(W(R.item));T&&*T)P.Image(X+180,390,160,180,*T);P.Text(X+20,600,FString::Printf(TEXT("%s %d / %s %d"),*H->ItemName("alloy"),R.alloy,*H->ItemName("cells"),R.cells),18);Button(X+20,660,485,60,L(Unlocked?TEXT("ue.manufacture"):TEXT("ue.research")),Unlocked?TEXT("manufacture"):TEXT("research"),W(Id),0,Unlocked);I++;}P.Text(130,810,FString::Printf(TEXT("%s: %d / %s: %d"),*H->ItemName("alloy"),S.available("alloy"),*H->ItemName("cells"),S.available("cells")),21,Muted);Button(90,925,250,60,L(TEXT("ue.back")),TEXT("page"),TEXT("home"));
|
||
}else if(Page==TEXT("inbox")){
|
||
Section(90,160,1740,720,L(TEXT("ue.pending")),L(TEXT("ue.inboxHint")));int I=0;for(const auto& Item:State.recoveryInbox){if(I>=10)break;float Y=285+I*50;P.Text(130,Y,H->ItemName(Item.itemId)+TEXT(" × ")+FString::FromInt(Item.count),20);Button(1050,Y,250,42,L(TEXT("ue.claim")),TEXT("claim"),W(Item.uid));Button(1330,Y,250,42,L(TEXT("ue.discard")),TEXT("discardInbox"),W(Item.uid));I++;}Button(130,810,400,48,L(TEXT("ue.claimAll")),TEXT("claim"));Button(90,925,250,60,L(TEXT("ue.back")),TEXT("page"),TEXT("hangar"));
|
||
}else if(Page==TEXT("settings")){
|
||
Section(80,150,1760,760,L(TEXT("ue.settings")),L(TEXT("ue.settingsHint")));static const TCHAR* Corners[]={TEXT("ue.perfTopRight"),TEXT("ue.perfTopLeft"),TEXT("ue.perfBottomRight"),TEXT("ue.perfBottomLeft")};Button(120,265,390,48,L(TEXT("ue.performance"))+TEXT(" ")+L(H->bShowPerformance?TEXT("ue.perfOn"):TEXT("ue.perfOff")),TEXT("performance"),TEXT(""),0,H->bShowPerformance);Button(540,265,460,48,L(TEXT("ue.perfPosition"))+TEXT(" ")+L(Corners[FMath::Clamp(H->PerformanceCorner,0,3)]),TEXT("performanceCorner"));P.Text(1030,279,L(TEXT("ue.perfHint")),14,Muted,740);P.Text(120,333,L(TEXT("ue.display")),23,Teal);int I=0;for(auto Resolution:{FIntPoint(1280,720),FIntPoint(1920,1080),FIntPoint(2560,1440),FIntPoint(3440,1440)}){Button(120,375+I*64,350,50,FString::Printf(TEXT("%d × %d"),Resolution.X,Resolution.Y),TEXT("resolution"),FString::Printf(TEXT("%dx%d"),Resolution.X,Resolution.Y));I++;}
|
||
Button(120,649,350,50,L(TEXT("ue.fullscreen")),TEXT("fullscreen"));P.Text(120,718,FString::Printf(TEXT("%s %.1f"),*L(TEXT("ue.sensitivity")),H->Sensitivity),18,Ink,235);Button(365,708,45,43,TEXT("−"),TEXT("sensitivity"),TEXT(""),-1);Button(425,708,45,43,TEXT("+"),TEXT("sensitivity"),TEXT(""),1);P.Text(120,770,FString::Printf(TEXT("%s %.1f"),*L(TEXT("ue.aimSensitivity")),H->AimSensitivity),18,Ink,235);Button(365,760,45,43,TEXT("−"),TEXT("aimSensitivity"),TEXT(""),-1);Button(425,760,45,43,TEXT("+"),TEXT("aimSensitivity"),TEXT(""),1);Button(120,825,350,48,L(TEXT("ue.invertY")),TEXT("invert"),TEXT(""),0,H->bInvertY);
|
||
P.Text(560,333,L(TEXT("ue.controls")),23,Teal);static const TCHAR* Names[]={TEXT("ue.forward"),TEXT("ue.backward"),TEXT("ue.left"),TEXT("ue.right"),TEXT("ue.jump"),TEXT("ue.boost"),TEXT("ue.guard"),TEXT("ue.reload"),TEXT("ue.view"),TEXT("ue.interact"),TEXT("ue.inventory"),TEXT("ue.pod"),TEXT("ue.secondary"),TEXT("ue.fire"),TEXT("ue.aim")};for(int J=0;J<H->Keys.Num();J++){float X=560+(J/8)*600,Y=375+(J%8)*64;P.Text(X,Y+10,L(Names[J]),18,Ink,225);Button(X+240,Y,300,48,C->Rebind==J?L(TEXT("ue.pressKey")):H->Keys[J],TEXT("rebind"),TEXT(""),J,C->Rebind==J);}
|
||
Button(80,945,270,58,L(TEXT("ue.back")),TEXT("page"),C->Mech()?TEXT("pause"):TEXT("home"));Button(1200,945,250,58,FString::Printf(TEXT("%s %d%%"),*L(TEXT("ue.volume")),FMath::RoundToInt(H->MasterVolume*100)),TEXT("volume"));Button(1480,945,360,58,L(TEXT("ue.quality")),TEXT("quality"));
|
||
}else if(Page==TEXT("pause")||Page==TEXT("upgrade")){
|
||
Section(580,220,760,630,L(Page==TEXT("pause")?TEXT("ue.paused"):TEXT("ue.upgrade")),L(TEXT("ue.pauseHint")));
|
||
if(Page==TEXT("pause")){Button(625,355,670,65,L(TEXT("ue.resume")),TEXT("page"),TEXT("play"),0,true);Button(625,440,670,65,L(TEXT("ue.inventory")),TEXT("page"),TEXT("inventory"));Button(625,525,670,65,L(TEXT("ue.settings")),TEXT("page"),TEXT("settings"));Button(625,610,670,65,L(TEXT("ue.saveAndHome")),TEXT("home"));}
|
||
else{for(int I=0;I<3;I++)Button(625,345+I*98,670,70,L(I==0?TEXT("ue.upgradeDamage"):I==1?TEXT("ue.upgradeRepair"):TEXT("ue.upgradeEnergy")),TEXT("upgrade"),TEXT(""),I);Button(625,690,670,55,L(TEXT("ue.back")),TEXT("page"),TEXT("play"));}
|
||
}else if(Play){
|
||
P.Rect(35,32,515,145,Panel);P.Rect(35,32,4,145,Teal);P.Text(60,50,H->Label(FString::Printf(TEXT("chassis.chassis_%d.name"),Run.chassis)),23,Teal);P.Text(60,90,FString::Printf(TEXT("%s %.0f / %s %.0f"),*L(TEXT("ue.armor")),Run.armor,*L(TEXT("ue.energy")),Run.energy),22);P.Rect(60,140,460,8,Line);P.Rect(60,140,460*FMath::Clamp(Run.armor/S.catalog().chassis[Run.chassis].armor,0.f,1.f),8,Teal);
|
||
P.Rect(1390,32,495,145,Panel);P.Text(1415,48,FString::Printf(TEXT("%s %d / 5 · %s %d"),*L(TEXT("ue.stage")),Run.stage+1,*L(TEXT("ue.salvage")),static_cast<int>(Run.cargo.size())),20,Teal);P.Text(1415,90,L(Run.routeCompleted?TEXT("ue.routeDone"):Run.objectiveDone?TEXT("ue.objectiveDone"):TEXT("ue.findObjective")),19,Ink,445);P.Text(1415,133,L(Run.podUsed?TEXT("ue.podUsed"):TEXT("ue.podAvailable")),15,Run.podUsed?Muted:Amber);
|
||
P.Rect(35,932,480,105,Panel);P.Text(60,951,FString::Printf(TEXT("%02d / %s"),H->Combat.rounds,*L(H->Combat.reload>0?TEXT("ue.reloading"):TEXT("ue.primary"))),27,Teal);P.Text(60,997,H->Keys[8]+TEXT(" ")+L(TEXT("ue.view"))+TEXT(" · ")+H->Keys[10]+TEXT(" ")+L(TEXT("ue.inventory")),14,Muted);
|
||
const FVector2D Aim=(G.GetLocalSize()*.5f-P.Origin)/P.Scale;P.Rect(Aim.X-2,Aim.Y-10,4,20,Teal);P.Rect(Aim.X-10,Aim.Y-2,20,4,Teal);if(auto M=GetWorld()->GetAuthGameMode<AIronsGameMode>()){P.Rect(550,955,800,65,Panel);P.Text(580,972,M->Prompt(),19,Ink,740);if(M->ExtractionWait>=0&&!M->bExtractionReady)P.Text(740,900,L(TEXT("ue.wait"))+FString::Printf(TEXT(" %.0fs"),M->ExtractionWait),25,Amber);if(M->PodProgress>0){P.Rect(650,850,620,9,Line);P.Rect(650,850,620*M->PodProgress/3,9,Amber);P.Text(650,810,L(TEXT("ue.podHolding")),20,Amber);}if(M->Escort)P.Text(650,210,FString::Printf(TEXT("%s %.0f / %.0f%%"),*L(TEXT("ue.escort")),Run.escortArmor,M->EscortProgress/45*100),19,Teal);}
|
||
if(H->IsTraining())P.Text(650,185,L(TEXT("ue.rangeStats"))+FString::Printf(TEXT(" %d / %d / %.1fs"),S.range().hits,S.range().gates,S.range().seconds),18,Teal,670);
|
||
int VX=0,VY=0;C->GetViewportSize(VX,VY);if(VX>0&&VY>0&&C->Mech())for(TActorIterator<AIronsMarker> It(GetWorld());It;++It){bool Course=It->Kind.StartsWith(TEXT("rangeGate"));if(It->IsHidden()&&!Course)continue;float Distance=FVector::Dist(It->GetActorLocation(),C->Mech()->GetActorLocation())*.01f;if(It->Kind==TEXT("loot")&&Distance>4.5f)continue;if(Course&&FCString::Atoi(*It->Kind.Right(1))!=S.range().gates)continue;if(It->Kind.StartsWith(TEXT("gate"))&&!Run.objectiveDone)continue;if(It->Kind==TEXT("objective")&&(Run.objectiveDone||(!H->IsTraining()&&Run.stage==4)))continue;if((It->Kind==TEXT("upgrade")||It->Kind==TEXT("rangeReset"))&&Distance>5)continue;FVector2D Screen;if(!C->ProjectWorldLocationToScreen(It->GetActorLocation()+FVector(0,0,180),Screen,true))continue;
|
||
FVector2D Point=(FVector2D(Screen.X*G.GetLocalSize().X/VX,Screen.Y*G.GetLocalSize().Y/VY)-P.Origin)/P.Scale;if(Point.X<20||Point.X>1900||Point.Y<190||Point.Y>890)continue;
|
||
FString Key=Course?TEXT("ue.courseGate"):It->Kind==TEXT("extract")?TEXT("ue.extraction"):It->Kind==TEXT("loot")?TEXT("ue.search"):It->Kind.StartsWith(TEXT("gate"))?(Run.stage==1?(It->Kind.EndsWith(TEXT("1"))?TEXT("ue.routeEscort"):TEXT("ue.routeBoss")):TEXT("ue.nextStage")):It->Kind==TEXT("objective")?TEXT("ue.activate"):It->Kind==TEXT("rangeReset")?TEXT("ue.rangeResetLabel"):TEXT("ue.upgrade");
|
||
P.Text(Point.X-90,Point.Y,H->Label(Key)+FString::Printf(TEXT(" %.0fm"),Distance),14,It->Kind==TEXT("loot")?Ink:Amber,210);
|
||
}
|
||
if(auto Mech=C->Mech();Mech&&GetWorld()->GetTimeSeconds()-Mech->DamageTime<.2f)P.Frame(0,0,1920,1080,FLinearColor(1,.15f,.1f));
|
||
}
|
||
if(!Play){P.Rect(0,1030,1920,50,FLinearColor(.015f,.026f,.035f,.97f));P.Text(42,1043,L(TEXT("ue.footer")),14,Muted);Button(1660,1035,220,39,TEXT("中文 / EN"),TEXT("language"));}
|
||
if(!H->bReady||(!H->StatusKey.IsEmpty()&&FPlatformTime::Seconds()<H->StatusUntil)){P.Rect(540,114,840,48,FLinearColor(.025f,.09f,.11f,.97f));FString Detail=H->StatusKey==TEXT("ue.loot")?H->ItemName(U(H->StatusDetail)):H->StatusDetail;P.Text(560,126,H->Label(H->StatusKey)+(Detail.IsEmpty()?TEXT(""):TEXT(" · ")+Detail),16,H->bReady?Teal:Amber,800);}
|
||
if(bDragging){const gf::Item* Item=gf::find(State.warehouse,U(DragUid));if(!Item)Item=gf::find(DragHold==gf::Hold::Cargo?Run.cargo:Run.safeCase,U(DragUid));if(Item){auto Size=gf::Grid::size(Item->itemId,bRotated);P.Rect(Pointer.X-Size.first*28,Pointer.Y-Size.second*28,Size.first*56,Size.second*56,FLinearColor(.16f,.5f,.5f,.7f));if(const auto* T=Icons.Find(W(Item->itemId));T&&*T)P.Image(Pointer.X-Size.first*28,Pointer.Y-Size.second*28,Size.first*56,Size.second*56,*T);}}
|
||
return P.Layer;
|
||
}
|
||
|
||
namespace {
|
||
FVector2D UiPoint(const FGeometry& G,FVector2D Absolute,const UIronsGameInstance* H){auto Layout=FIronsPerformanceLayout::Make(G.GetLocalSize(),H&&H->bShowPerformance,H?H->PerformanceCorner:0);return (G.AbsoluteToLocal(Absolute)-Layout.ContentOrigin)/Layout.ContentScale;}
|
||
}
|
||
void UIronsScreen::Dispatch(const FIronsHitRegion& Hit){
|
||
auto H=Host();auto C=Controller();if(!H||!C)return;auto& S=H->Core();auto Cmd=Hit.Command;auto Uid=U(Selected);
|
||
if(Cmd==TEXT("page")){C->SetPage(Hit.Argument);return;}
|
||
if(Cmd==TEXT("language")){H->SetLanguage(!H->bEnglish);return;}
|
||
if(Cmd==TEXT("performance")){H->bShowPerformance=!H->bShowPerformance;H->SavePreferences();return;}
|
||
if(Cmd==TEXT("performanceCorner")){H->PerformanceCorner=(H->PerformanceCorner+1)%4;H->SavePreferences();return;}
|
||
if(Cmd==TEXT("launch")){C->Launch();return;}
|
||
if(Cmd==TEXT("training")){C->Launch(true);return;}
|
||
if(Cmd==TEXT("quit")){UKismetSystemLibrary::QuitGame(this,C,EQuitPreference::Quit,false);return;}
|
||
if(Cmd==TEXT("home")){C->ReturnHome();return;}
|
||
if(Cmd==TEXT("scroll")){Scroll=FMath::Clamp(Scroll+Hit.A,0,12);return;}
|
||
if(Cmd==TEXT("details")){bDetails=!bDetails;return;}
|
||
if(Cmd==TEXT("podMode")){bPodSelect=!bPodSelect;return;}
|
||
if(Cmd==TEXT("quantity")){const gf::Item* I=gf::find(S.state().warehouse,Uid);if(!I)I=gf::find(SelectedHold==gf::Hold::Cargo?S.state().run.cargo:S.state().run.safeCase,Uid);Quantity=FMath::Clamp(Quantity+Hit.A,1,I?I->count:1);return;}
|
||
if(Cmd==TEXT("slot")){Selected.Empty();SelectedSlot=Hit.A;return;}
|
||
if(Cmd==TEXT("item")){Selected=Hit.Argument;SelectedSlot=-1;SelectedHold=static_cast<gf::Hold>(Hit.A);const gf::Item* I=gf::find(S.state().warehouse,U(Selected));if(!I)I=gf::find(SelectedHold==gf::Hold::Cargo?S.state().run.cargo:S.state().run.safeCase,U(Selected));Quantity=I?I->count:1;bRotated=I&&I->rotated;
|
||
if(bPodSelect&&SelectedHold==gf::Hold::Cargo){if(PodSelection.Contains(Selected))PodSelection.Remove(Selected);else if(PodSelection.Num()<4)PodSelection.Add(Selected);}return;}
|
||
if(Cmd==TEXT("settings")){C->SetPage(TEXT("settings"));return;}
|
||
if(Cmd==TEXT("rebind")){C->Rebind=Hit.A;return;}
|
||
if(Cmd==TEXT("sensitivity")){H->Sensitivity=FMath::Clamp(H->Sensitivity+.1f*Hit.A,.1f,5.f);H->SavePreferences();return;}
|
||
if(Cmd==TEXT("aimSensitivity")){H->AimSensitivity=FMath::Clamp(H->AimSensitivity+.1f*Hit.A,.1f,2.f);H->SavePreferences();return;}
|
||
if(Cmd==TEXT("invert")){H->bInvertY=!H->bInvertY;H->SavePreferences();return;}
|
||
if(Cmd==TEXT("volume")){H->MasterVolume+=.1f;if(H->MasterVolume>1.01f)H->MasterVolume=0;H->SavePreferences();return;}
|
||
auto Settings=UGameUserSettings::GetGameUserSettings();
|
||
if(Cmd==TEXT("resolution")){FString X,Y;Hit.Argument.Split(TEXT("x"),&X,&Y);Settings->SetScreenResolution(FIntPoint(FCString::Atoi(*X),FCString::Atoi(*Y)));Settings->SetFullscreenMode(EWindowMode::Windowed);Settings->ApplySettings(false);return;}
|
||
if(Cmd==TEXT("fullscreen")){Settings->SetFullscreenMode(Settings->GetFullscreenMode()==EWindowMode::Windowed?EWindowMode::WindowedFullscreen:EWindowMode::Windowed);Settings->ApplySettings(false);return;}
|
||
if(Cmd==TEXT("quality")){int Quality=(Settings->GetOverallScalabilityLevel()+1)%4;Settings->SetOverallScalabilityLevel(Quality);Settings->ApplySettings(false);H->Notice(TEXT("ue.quality"),FString::FromInt(Quality));return;}
|
||
if(!H->bReady)return;
|
||
if(C->Page==TEXT("hangar")&&S.state().run.active){H->Notice(TEXT("ue.locked"));return;}
|
||
gf::Result Result=gf::Result::fail(gf::Code::Invalid);
|
||
if(Cmd==TEXT("chassis"))Result=S.selectChassis(Hit.A);
|
||
else if(Cmd==TEXT("borrow"))Result=S.borrow(Hit.A);
|
||
else if(Cmd==TEXT("equip"))Result=S.equip(Uid);
|
||
else if(Cmd==TEXT("install"))Result=S.install(Uid,SelectedHold);
|
||
else if(Cmd==TEXT("uninstall")){
|
||
auto SlotIndex=Hit.A;auto Part=S.catalog().part(SlotIndex,S.state().run.equipment[SlotIndex]);if(Part){auto Item=gf::Item{};Item.itemId=Part->id;auto Grid=S.state().run.cargo;bool Found=false;for(int Y=0;Y<4&&!Found;Y++)for(int X=0;X<4&&!Found;X++)if(gf::Grid::fits(Grid,4,4,Item,X,Y,false)){Result=S.uninstall(SlotIndex,gf::Hold::Cargo,X,Y);Found=true;}if(!Found)Result=gf::Result::fail(gf::Code::NoSpace);}
|
||
}
|
||
else if(Cmd==TEXT("prepare"))Result=S.prepare(Uid,Hit.A?gf::Hold::SafeCase:gf::Hold::Cargo,bRotated,-1,-1,Quantity);
|
||
else if(Cmd==TEXT("unprepare"))Result=S.unprepare(Uid);
|
||
else if(Cmd==TEXT("transfer"))Result=S.moveItem(Uid,SelectedHold,SelectedHold==gf::Hold::Cargo?gf::Hold::SafeCase:gf::Hold::Cargo,-1,-1,bRotated,Quantity);
|
||
else if(Cmd==TEXT("sort"))Result=S.sortWarehouse();
|
||
else if(Cmd==TEXT("claim"))Result=S.claim(U(Hit.Argument));
|
||
else if(Cmd==TEXT("discardInbox")){if(Selected==Hit.Argument){Result=S.discard(U(Hit.Argument),true);Selected.Empty();}else{Selected=Hit.Argument;H->Notice(TEXT("ue.confirmDiscard"));return;}}
|
||
else if(Cmd==TEXT("research"))Result=S.research(U(Hit.Argument));
|
||
else if(Cmd==TEXT("manufacture"))Result=S.manufacture(U(Hit.Argument));
|
||
else if(Cmd==TEXT("recycle"))Result=S.recycle(Uid);
|
||
else if(Cmd==TEXT("upgrade")){Result=S.upgrade(Hit.A);if(Result)C->SetPage(TEXT("play"));}
|
||
H->Accept(Result);
|
||
}
|
||
FReply UIronsScreen::NativeOnMouseButtonDown(const FGeometry& G,const FPointerEvent& E){
|
||
Pointer=UiPoint(G,E.GetScreenSpacePosition(),Host());if(Controller()->Rebind>=0){Controller()->ProcessKey(E.GetEffectingButton(),true);return FReply::Handled();}if(E.GetEffectingButton()!=EKeys::LeftMouseButton)return FReply::Handled();
|
||
for(int I=Hits.Num()-1;I>=0;I--)if(Hits[I].Rect.ContainsPoint(Pointer)){auto Hit=Hits[I];if(Hit.Command==TEXT("item")){Dispatch(Hit);DragUid=Hit.Argument;DragHold=static_cast<gf::Hold>(Hit.A);DragStart=Pointer;bDragging=false;}else Dispatch(Hit);return FReply::Handled().SetUserFocus(TakeWidget(),EFocusCause::Mouse).CaptureMouse(TakeWidget());}
|
||
return FReply::Handled().SetUserFocus(TakeWidget(),EFocusCause::Mouse);
|
||
}
|
||
FReply UIronsScreen::NativeOnMouseMove(const FGeometry& G,const FPointerEvent& E){Pointer=UiPoint(G,E.GetScreenSpacePosition(),Host());if(!DragUid.IsEmpty()&&(Pointer-DragStart).Size()>8&&!bPodSelect)bDragging=true;return FReply::Handled();}
|
||
FReply UIronsScreen::NativeOnMouseButtonUp(const FGeometry& G,const FPointerEvent& E){
|
||
Pointer=UiPoint(G,E.GetScreenSpacePosition(),Host());auto H=Host();auto C=Controller();if(H&&C&&bDragging&&!DragUid.IsEmpty()){
|
||
auto& S=H->Core();gf::Result R=gf::Result::fail(gf::Code::Invalid);bool Applied=false;
|
||
if(C->Page==TEXT("hangar")&&S.state().run.active){H->Notice(TEXT("ue.locked"));}
|
||
else{
|
||
for(const auto& Hit:Hits)if(Hit.Command==TEXT("slot")&&Hit.Rect.ContainsPoint(Pointer)){R=S.state().run.active?S.install(U(DragUid),DragHold):S.equip(U(DragUid));Applied=true;break;}
|
||
for(const auto& Grid:Grids)if(!Applied&&Grid.Rect.ContainsPoint(Pointer)){
|
||
int X=FMath::FloorToInt((Pointer.X-Grid.Rect.Left)/Grid.Cell),Y=FMath::FloorToInt((Pointer.Y-Grid.Rect.Top)/Grid.Cell)+(Grid.Hold==gf::Hold::Warehouse?Scroll:0);
|
||
const gf::Item* Target=nullptr;const auto& Items=Grid.Hold==gf::Hold::Warehouse?S.state().warehouse:Grid.Hold==gf::Hold::Cargo?S.state().run.cargo:S.state().run.safeCase;
|
||
for(const auto& I:Items){auto Size=gf::Grid::size(I.itemId,I.rotated);if(I.uid!=U(DragUid)&&X>=I.x&&X<I.x+Size.first&&Y>=I.y&&Y<I.y+Size.second){Target=&I;break;}}
|
||
if(Target&&Grid.Hold==gf::Hold::Warehouse&&DragHold==gf::Hold::Warehouse)R=S.mergeWarehouse(U(DragUid),Target->uid,Quantity);
|
||
else if(Target&&S.state().run.active&&Grid.Hold!=gf::Hold::Warehouse){const auto* Source=gf::find(DragHold==gf::Hold::Cargo?S.state().run.cargo:S.state().run.safeCase,U(DragUid));R=Source&&Source->itemId==Target->itemId&&gf::Grid::material(Source->itemId)?S.mergeItem(U(DragUid),DragHold,Target->uid,Grid.Hold,Quantity):S.swapItems(U(DragUid),DragHold,Target->uid,Grid.Hold,bRotated);}
|
||
else if(Grid.Hold==gf::Hold::Warehouse)R=DragHold==gf::Hold::Warehouse?S.moveWarehouse(U(DragUid),X,Y,bRotated,Quantity):S.unprepare(U(DragUid));
|
||
else if(!S.state().run.active)R=S.prepare(U(DragUid),Grid.Hold,bRotated,X,Y,Quantity);
|
||
else R=S.moveItem(U(DragUid),DragHold,Grid.Hold,X,Y,bRotated,Quantity);
|
||
Applied=true;
|
||
}
|
||
if(Applied)H->Accept(R);
|
||
}
|
||
}
|
||
bDragging=false;DragUid.Empty();return FReply::Handled().ReleaseMouseCapture();
|
||
}
|
||
FReply UIronsScreen::NativeOnMouseWheel(const FGeometry& G,const FPointerEvent& E){Pointer=UiPoint(G,E.GetScreenSpacePosition(),Host());if(Pointer.X>1100&&Controller()->Page==TEXT("hangar"))Scroll=FMath::Clamp(Scroll-FMath::RoundToInt(E.GetWheelDelta()*3),0,12);return FReply::Handled();}
|
||
FReply UIronsScreen::NativeOnKeyDown(const FGeometry& G,const FKeyEvent& E){
|
||
auto C=Controller();if(!C)return FReply::Unhandled();if(C->Rebind>=0){C->ProcessKey(E.GetKey(),true);return FReply::Handled();}
|
||
if(bDragging&&E.GetKey()==EKeys::R){bRotated=!bRotated;return FReply::Handled();}
|
||
if(E.GetKey()==EKeys::Escape){if(bDragging){bDragging=false;DragUid.Empty();}else C->Menu();return FReply::Handled();}
|
||
if(C->Page==TEXT("inventory")&&E.GetKey()==FKey(*Host()->Keys[10])){C->SetPage(TEXT("play"));return FReply::Handled();}
|
||
return Super::NativeOnKeyDown(G,E);
|
||
}
|