AI захватит мир

This commit is contained in:
Oscar
2025-06-26 23:24:52 +03:00
parent 793165bb03
commit 875d594038
28 changed files with 1263 additions and 266 deletions

View File

@@ -4,11 +4,31 @@
<root class="inventory @( Inventar.IsInventoryOpen ? "" : "hidden" )">
<div class="inventory-panel">
@if ( PlayerInventory.Items.Count > 0 )
@if ( PlayerInventory != null )
{
@foreach ( var item in PlayerInventory.Items )
<div class="inventory-header">
<div class="inventory-title">Инвентарь</div>
@if ( !PlayerInventory.UnlimitedSlots )
{
<div class="inventory-slots">
@PlayerInventory.GetUsedSlots() / @PlayerInventory.MaxInventorySlots слотов
<div class="inventory-usage-bar">
<div class="inventory-usage-fill" style="width: @(PlayerInventory.GetInventoryUsagePercentage())%"></div>
</div>
</div>
}
</div>
@if ( PlayerInventory.Items.Count > 0 )
{
<Sasalka.Ui.InventoryItem Item="@item" OnItemClick="@( UseItem )" OnItemRightClick="@( DropItem )"/>
@foreach ( var item in PlayerInventory.Items )
{
<Sasalka.Ui.InventoryItem Item="@item" OnItemClick="@( UseItem )" OnItemRightClick="@( DropItem )"/>
}
}
else
{
<div class="inventory-empty">Инвентарь пуст</div>
}
}
</div>

View File

@@ -24,6 +24,59 @@ Inventory {
//background-color: rgba(255, 0, 0, 0.1);
}
.inventory-header {
display: flex;
flex-direction: column;
gap: 8px;
padding-bottom: 16px;
border-bottom: 2px solid #2a3d54;
margin-bottom: 16px;
}
.inventory-title {
font-size: 24px;
font-weight: bold;
color: #ffffff;
text-align: center;
text-shadow: 0 0 10px rgba(255, 255, 255, 0.3);
}
.inventory-slots {
display: flex;
flex-direction: column;
gap: 6px;
align-items: center;
}
.inventory-slots {
font-size: 14px;
color: #a0b4c8;
text-align: center;
}
.inventory-usage-bar {
width: 100%;
height: 8px;
background: rgba(42, 61, 84, 0.5);
border-radius: 4px;
overflow: hidden;
border: 1px solid #2a3d54;
}
.inventory-usage-fill {
height: 100%;
background: linear-gradient(90deg, #4CAF50 0%, #8BC34A 100%);
transition: width 0.3s ease;
border-radius: 3px;
}
.inventory-empty {
text-align: center;
color: #a0b4c8;
font-style: italic;
padding: 40px 20px;
font-size: 16px;
}
.hidden {
opacity: 0;

View File

@@ -12,25 +12,50 @@
: !string.IsNullOrWhiteSpace( definition?.ImageUrl )
? definition.ImageUrl
: null;
var rarityColor = definition?.GetRarityColor() ?? "#ffffff";
var categoryIcon = definition?.GetCategoryIcon() ?? "📦";
}
<root class="inventory-item @( Item.Equipped ? "equipped" : "" )" @onclick="@(() => OnItemClick?.Invoke( Item ))" @onrightclick=@( () => OnItemRightClick?.Invoke( Item ) )>
@if ( slot is not null )
{
<div class="inventory-item__slot">@slot</div>
}
<root class="inventory-item @( Item.Equipped ? "equipped" : "" )"
@onclick="@(() => OnItemClick?.Invoke( Item ))"
@onrightclick="@( () => OnItemRightClick?.Invoke( Item ) )"
style="border-left-color: @rarityColor;">
@if ( !string.IsNullOrEmpty( imageUrl ) )
{
<img src="@imageUrl" alt="@name"/>
}
<div class="inventory-item__icon">
@if ( !string.IsNullOrEmpty( imageUrl ) )
{
<img src="@imageUrl" alt="@name"/>
}
else
{
<span class="category-icon">@categoryIcon</span>
}
</div>
<div class="inventory-item__name">@name</div>
<div class="inventory-item__info">
<div class="inventory-item__name" style="color: @rarityColor;">@name</div>
@if ( definition?.Category != ItemCategory.Misc )
{
<div class="inventory-item__category">@definition?.Category</div>
}
</div>
@if ( definition?.MaxCount > 1 )
{
<div class="inventory-item__count">@Item?.Count / @definition.MaxCount</div>
}
<div class="inventory-item__meta">
@if ( slot is not null )
{
<div class="inventory-item__slot">@GetSlotName( slot.Value )</div>
}
@if ( definition?.MaxCount > 1 )
{
<div class="inventory-item__count">@Item?.Count / @definition.MaxCount</div>
}
@* @if ( Item?.Equipped == true ) *@
@* { *@
@* <div class="inventory-item__equipped">✓</div> *@
@* } *@
</div>
</root>
@code {
@@ -38,11 +63,28 @@
public Action<Sasalka.InventoryItem> OnItemClick { get; set; }
public Action<Sasalka.InventoryItem> OnItemRightClick { get; set; }
string GetSlotName( Inventar.InventorySlot slot )
{
return slot switch
{
Inventar.InventorySlot.LeftHand => "Л.Рука",
Inventar.InventorySlot.RightHand => "П.Рука",
Inventar.InventorySlot.Head => "Голова",
Inventar.InventorySlot.Body => "Тело",
Inventar.InventorySlot.Hands => "Руки",
Inventar.InventorySlot.Bottom => "Ноги",
Inventar.InventorySlot.Feet => "Обувь",
_ => "Неизвестно"
};
}
protected override int BuildHash()
{
base.BuildHash();
var hash = new HashCode();
hash.Add( Item?.Count );
hash.Add( Item?.Equipped );
hash.Add( Item?.Definition?.Name );
return hash.ToHashCode();
}

View File

@@ -1,49 +1,154 @@
InventoryItem {
.inventory-item {
flex-shrink: 0;
width: 100%;
background: #2a3d53;
background: linear-gradient(135deg, #2a3d53 0%, #1f2d3f 100%);
display: flex;
gap: 24px;
gap: 16px;
align-items: center;
justify-content: flex-start;
border: 1px solid #666;
border-left: 4px solid #ffffff;
border-radius: 12px;
padding: 12px 24px;
padding: 16px;
cursor: pointer;
transition: background 0.2s ease;
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
position: relative;
//box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
&:hover {
background: #444;
background: linear-gradient(135deg, #3a4d63 0%, #2f3d4f 100%);
transform: translateY(-2px);
//box-shadow: 0 6px 16px rgba(0, 0, 0, 0.3);
border-color: #888;
}
img {
width: 32px;
height: 32px;
object-fit: contain;
}
.inventory-item__name {
font-size: 20px;
font-weight: 500;
}
.inventory-item__count {
margin-left: auto;
font-size: 14px;
color: #ccc;
}
.inventory-item__slot {
font-size: 12px;
color: #8fc98f;
background: rgba(0, 0, 0, 0.3);
padding: 2px 6px;
border-radius: 4px;
&:active {
transform: translateY(0);
//box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
}
&.equipped {
border: 2px solid #4caf50;
background: #2e3e2e;
background: linear-gradient(135deg, #2e3e2e 0%, #1f2d1f 100%);
//box-shadow: 0 4px 12px rgba(76, 175, 80, 0.3);
&:hover {
background: linear-gradient(135deg, #3e4e3e 0%, #2f3d2f 100%);
//box-shadow: 0 6px 16px rgba(76, 175, 80, 0.4);
}
.inventory-item__name {
color: #4caf50;
}
}
.inventory-item__icon {
flex-shrink: 0;
width: 48px;
height: 48px;
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, #1a2a3a 0%, #0f1a2a 100%);
border-radius: 8px;
border: 1px solid #3a4a5a;
//box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.3);
img {
width: 32px;
height: 32px;
object-fit: contain;
//filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.5));
}
.category-icon {
font-size: 24px;
//filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.5));
}
}
.inventory-item__info {
flex: 1;
min-width: 0;
gap: 20px;
.inventory-item__name {
font-size: 16px;
font-weight: 600;
margin-bottom: 4px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
//text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
}
.inventory-item__description {
font-size: 12px;
color: #cccccc;
margin-bottom: 4px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
opacity: 0.8;
}
.inventory-item__category {
font-size: 10px;
color: #8fc98f;
background: linear-gradient(135deg, rgba(143, 201, 143, 0.2) 0%, rgba(143, 201, 143, 0.1) 100%);
padding: 2px 8px;
border-radius: 4px;
display: inline-block;
border: 1px solid rgba(143, 201, 143, 0.3);
text-transform: uppercase;
letter-spacing: 0.5px;
font-weight: 500;
}
}
.inventory-item__meta {
display: flex;
flex-direction: column;
align-items: flex-end;
gap: 4px;
.inventory-item__slot {
font-size: 10px;
color: #8fc98f;
background: linear-gradient(135deg, rgba(143, 201, 143, 0.3) 0%, rgba(143, 201, 143, 0.2) 100%);
padding: 2px 8px;
border-radius: 4px;
font-weight: 500;
border: 1px solid rgba(143, 201, 143, 0.4);
text-transform: uppercase;
letter-spacing: 0.5px;
}
.inventory-item__count {
font-size: 12px;
color: #cccccc;
font-weight: 500;
background: rgba(0, 0, 0, 0.2);
padding: 2px 6px;
border-radius: 4px;
border: 1px solid rgba(255, 255, 255, 0.1);
}
.inventory-item__equipped {
font-size: 14px;
color: #4caf50;
font-weight: bold;
//text-shadow: 0 1px 2px rgba(76, 175, 80, 0.5);
animation: pulse 2s infinite;
}
}
}
@keyframes pulse {
0%, 100% {
opacity: 1;
}
50% {
opacity: 0.7;
}
}