Prepicked plants editor

This commit is contained in:
Rendo 2025-07-29 04:08:05 +05:00
commit 56f75a5d06
43 changed files with 532 additions and 50 deletions

View file

@ -0,0 +1,47 @@
[gd_scene load_steps=4 format=3 uid="uid://dwbqlfs51en62"]
[ext_resource type="Texture2D" uid="uid://dxyf557m4mq1p" path="res://assets/sprites/gui/EmptyPlantCard.png" id="1_dmimt"]
[ext_resource type="Texture2D" uid="uid://cabpf23ndlvx0" path="res://assets/sprites/gui/Selection.tres" id="2_0vy3a"]
[ext_resource type="Script" uid="uid://bhah157u6q56b" path="res://addons/pvzadventure/scripts/seedpacket-editor/DnDSeedpacket.cs" id="3_61l76"]
[node name="EditorSeedpacket" type="TextureButton" node_paths=PackedStringArray("preview")]
anchors_preset = -1
anchor_right = 0.103667
anchor_bottom = 0.21
offset_right = -0.199997
mouse_default_cursor_shape = 2
texture_normal = ExtResource("1_dmimt")
texture_focused = ExtResource("2_0vy3a")
stretch_mode = 0
script = ExtResource("3_61l76")
preview = NodePath("PlantPreviewContainer/Preview")
metadata/_edit_use_anchors_ = true
[node name="PlantPreviewContainer" type="Control" parent="."]
clip_contents = true
layout_mode = 1
anchor_left = -0.061
anchor_top = -0.036
anchor_right = 1.061
anchor_bottom = 0.661
offset_left = 0.00199986
offset_top = 0.0320001
offset_right = -0.0019989
offset_bottom = -0.0319977
mouse_filter = 2
[node name="Preview" type="TextureRect" parent="PlantPreviewContainer"]
layout_mode = 1
anchors_preset = -1
anchor_left = 0.185
anchor_top = 0.205
anchor_right = 0.815
anchor_bottom = 1.333
offset_left = -0.0200005
offset_top = 0.00999928
offset_right = 0.0199966
offset_bottom = 0.0259933
mouse_filter = 2
mouse_default_cursor_shape = 2
expand_mode = 1
stretch_mode = 5

View file

@ -0,0 +1,55 @@
[gd_scene load_steps=4 format=3 uid="uid://dymyownbt688c"]
[ext_resource type="Texture2D" uid="uid://dxyf557m4mq1p" path="res://assets/sprites/gui/EmptyPlantCard.png" id="1_x27jk"]
[ext_resource type="Texture2D" uid="uid://cabpf23ndlvx0" path="res://assets/sprites/gui/Selection.tres" id="2_m8071"]
[ext_resource type="Texture2D" uid="uid://cjkwy3u0wuax3" path="res://assets/sprites/gui/ForbiddenPacket.tres" id="3_ji8qd"]
[node name="EditorSeedpacket" type="TextureButton"]
anchors_preset = -1
anchor_right = 0.137
anchor_bottom = 0.28
offset_right = -0.199997
mouse_default_cursor_shape = 2
texture_normal = ExtResource("1_x27jk")
texture_focused = ExtResource("2_m8071")
stretch_mode = 0
metadata/_edit_use_anchors_ = true
[node name="PlantPreviewContainer" type="Control" parent="."]
clip_contents = true
layout_mode = 1
anchor_left = -0.061
anchor_top = -0.036
anchor_right = 1.061
anchor_bottom = 0.661
offset_left = 0.00199986
offset_top = 0.0320001
offset_right = -0.0019989
offset_bottom = -0.0319977
mouse_filter = 2
[node name="Preview" type="TextureRect" parent="PlantPreviewContainer"]
layout_mode = 1
anchors_preset = -1
anchor_left = 0.185
anchor_top = 0.205
anchor_right = 0.815
anchor_bottom = 1.333
offset_left = -0.0200005
offset_top = 0.00999928
offset_right = 0.0199966
offset_bottom = 0.0259933
mouse_filter = 2
mouse_default_cursor_shape = 2
expand_mode = 1
stretch_mode = 5
[node name="ForbiddenTexture" type="TextureRect" parent="."]
visible = false
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
texture = ExtResource("3_ji8qd")

View file

@ -0,0 +1,152 @@
[gd_scene load_steps=3 format=3 uid="uid://drc0o8du38apr"]
[ext_resource type="PackedScene" uid="uid://dwbqlfs51en62" path="res://addons/pvzadventure/scenes/seedpack-editor/editor_seedpacket.tscn" id="1_m5lsd"]
[ext_resource type="Script" uid="uid://d1ks2q0c3eu0v" path="res://addons/pvzadventure/scripts/seedpacket-editor/SeedpacketEditor.cs" id="1_vrmxn"]
[node name="SeedpacketEditor" type="ScrollContainer"]
texture_filter = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
horizontal_scroll_mode = 0
script = ExtResource("1_vrmxn")
metadata/_edit_lock_ = true
[node name="VBoxContainer" type="VBoxContainer" parent="."]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
metadata/_edit_lock_ = true
[node name="PrepickedPlants" type="VBoxContainer" parent="VBoxContainer"]
layout_mode = 2
size_flags_vertical = 3
[node name="Label" type="Label" parent="VBoxContainer/PrepickedPlants"]
layout_mode = 2
text = "Prepicked plants"
horizontal_alignment = 1
vertical_alignment = 1
[node name="PrepickedContainer" type="HBoxContainer" parent="VBoxContainer/PrepickedPlants"]
unique_name_in_owner = true
layout_mode = 2
size_flags_vertical = 3
alignment = 1
[node name="Slot1" type="AspectRatioContainer" parent="VBoxContainer/PrepickedPlants/PrepickedContainer"]
layout_mode = 2
size_flags_horizontal = 3
ratio = 0.7321
[node name="Seedpacket" parent="VBoxContainer/PrepickedPlants/PrepickedContainer/Slot1" instance=ExtResource("1_m5lsd")]
layout_mode = 2
[node name="Slot2" type="AspectRatioContainer" parent="VBoxContainer/PrepickedPlants/PrepickedContainer"]
layout_mode = 2
size_flags_horizontal = 3
ratio = 0.7321
[node name="Seedpacket" parent="VBoxContainer/PrepickedPlants/PrepickedContainer/Slot2" instance=ExtResource("1_m5lsd")]
layout_mode = 2
[node name="Slot3" type="AspectRatioContainer" parent="VBoxContainer/PrepickedPlants/PrepickedContainer"]
layout_mode = 2
size_flags_horizontal = 3
ratio = 0.7321
[node name="Seedpacket" parent="VBoxContainer/PrepickedPlants/PrepickedContainer/Slot3" instance=ExtResource("1_m5lsd")]
layout_mode = 2
[node name="Slot4" type="AspectRatioContainer" parent="VBoxContainer/PrepickedPlants/PrepickedContainer"]
layout_mode = 2
size_flags_horizontal = 3
ratio = 0.7321
[node name="Seedpacket" parent="VBoxContainer/PrepickedPlants/PrepickedContainer/Slot4" instance=ExtResource("1_m5lsd")]
layout_mode = 2
[node name="Slot5" type="AspectRatioContainer" parent="VBoxContainer/PrepickedPlants/PrepickedContainer"]
layout_mode = 2
size_flags_horizontal = 3
ratio = 0.7321
[node name="Seedpacket" parent="VBoxContainer/PrepickedPlants/PrepickedContainer/Slot5" instance=ExtResource("1_m5lsd")]
layout_mode = 2
[node name="Slot6" type="AspectRatioContainer" parent="VBoxContainer/PrepickedPlants/PrepickedContainer"]
layout_mode = 2
size_flags_horizontal = 3
ratio = 0.7321
[node name="Seedpacket" parent="VBoxContainer/PrepickedPlants/PrepickedContainer/Slot6" instance=ExtResource("1_m5lsd")]
layout_mode = 2
[node name="Slot7" type="AspectRatioContainer" parent="VBoxContainer/PrepickedPlants/PrepickedContainer"]
layout_mode = 2
size_flags_horizontal = 3
ratio = 0.7321
[node name="Seedpacket" parent="VBoxContainer/PrepickedPlants/PrepickedContainer/Slot7" instance=ExtResource("1_m5lsd")]
layout_mode = 2
[node name="Slot8" type="AspectRatioContainer" parent="VBoxContainer/PrepickedPlants/PrepickedContainer"]
layout_mode = 2
size_flags_horizontal = 3
ratio = 0.7321
[node name="Seedpacket" parent="VBoxContainer/PrepickedPlants/PrepickedContainer/Slot8" instance=ExtResource("1_m5lsd")]
layout_mode = 2
[node name="Slot9" type="AspectRatioContainer" parent="VBoxContainer/PrepickedPlants/PrepickedContainer"]
layout_mode = 2
size_flags_horizontal = 3
ratio = 0.7321
[node name="Seedpacket" parent="VBoxContainer/PrepickedPlants/PrepickedContainer/Slot9" instance=ExtResource("1_m5lsd")]
layout_mode = 2
[node name="ForbiddenTags" type="VBoxContainer" parent="VBoxContainer"]
visible = false
layout_mode = 2
size_flags_vertical = 3
[node name="Label" type="Label" parent="VBoxContainer/ForbiddenTags"]
layout_mode = 2
text = "Forbidden tags"
horizontal_alignment = 1
vertical_alignment = 1
[node name="TagsContainer" type="GridContainer" parent="VBoxContainer/ForbiddenTags"]
unique_name_in_owner = true
layout_mode = 2
size_flags_vertical = 3
columns = 9
[node name="ForbiddenPlants" type="VBoxContainer" parent="VBoxContainer"]
layout_mode = 2
size_flags_vertical = 3
[node name="Label" type="Label" parent="VBoxContainer/ForbiddenPlants"]
layout_mode = 2
text = "Forbidden plants"
horizontal_alignment = 1
vertical_alignment = 1
[node name="FPlantsContainer" type="GridContainer" parent="VBoxContainer/ForbiddenPlants"]
unique_name_in_owner = true
layout_mode = 2
size_flags_vertical = 3
columns = 9
[connection signal="SaveCallback" from="VBoxContainer/PrepickedPlants/PrepickedContainer/Slot1/Seedpacket" to="." method="Save"]
[connection signal="SaveCallback" from="VBoxContainer/PrepickedPlants/PrepickedContainer/Slot2/Seedpacket" to="." method="Save"]
[connection signal="SaveCallback" from="VBoxContainer/PrepickedPlants/PrepickedContainer/Slot3/Seedpacket" to="." method="Save"]
[connection signal="SaveCallback" from="VBoxContainer/PrepickedPlants/PrepickedContainer/Slot4/Seedpacket" to="." method="Save"]
[connection signal="SaveCallback" from="VBoxContainer/PrepickedPlants/PrepickedContainer/Slot5/Seedpacket" to="." method="Save"]
[connection signal="SaveCallback" from="VBoxContainer/PrepickedPlants/PrepickedContainer/Slot6/Seedpacket" to="." method="Save"]
[connection signal="SaveCallback" from="VBoxContainer/PrepickedPlants/PrepickedContainer/Slot7/Seedpacket" to="." method="Save"]
[connection signal="SaveCallback" from="VBoxContainer/PrepickedPlants/PrepickedContainer/Slot8/Seedpacket" to="." method="Save"]
[connection signal="SaveCallback" from="VBoxContainer/PrepickedPlants/PrepickedContainer/Slot9/Seedpacket" to="." method="Save"]

View file

@ -0,0 +1,16 @@
using Godot;
[Tool]
public abstract partial class BaseEditor : Node
{
public AdventureLevelResource editedResource;
[Signal] public delegate void SaveCallbackEventHandler();
public virtual void SetEditedData(AdventureLevelResource data)
{
editedResource = data;
}
public virtual void Save()
{
EmitSignal(SignalName.SaveCallback);
}
}

View file

@ -0,0 +1 @@
uid://dxtrrfg1pba4p

View file

@ -0,0 +1,5 @@
public abstract partial class BaseWaveEditor : BaseEditor
{
public WaveData editedWave;
public abstract void SetEditedWave(WaveData wave);
}

View file

@ -0,0 +1 @@
uid://b23csior6audk

View file

@ -1,10 +1,8 @@
using Godot;
[Tool]
public partial class InitialEditor : Node
public partial class InitialEditor : BaseEditor
{
public AdventureLevelResource editedResource;
[Signal] public delegate void SaveCallbackEventHandler();
public override void _Ready()
{
foreach (var child in GetChild(0).GetChildren())
@ -15,7 +13,7 @@ public partial class InitialEditor : Node
}
}
}
public void SetData(AdventureLevelResource resource)
public override void SetEditedData(AdventureLevelResource resource)
{
editedResource = resource;
for (int i = 0; i < GetChild(0).GetChildCount(); i++)

View file

@ -11,8 +11,10 @@ public partial class AdventureResourceInspector : Node
const string ZOMBIES_ITEM_NAME = "Zombies";
const string EVENTS_ITEM_NAME = "Events";
const string HUGEWAVE_ITEM_NAME = "Is huge wave?";
const string SEEDPACKETS_ITEM_NAME = "Seedpackets editor";
private PackedScene zombieEditorScene = ResourceLoader.Load<PackedScene>("uid://db5ah76l43ng2");
private PackedScene initialEditorScene = ResourceLoader.Load<PackedScene>("uid://sqessjn0m4o3");
private PackedScene seedpacketEditorScene = ResourceLoader.Load<PackedScene>("uid://drc0o8du38apr");
private Tree tree;
private AdventureLevelResource heldResource;
@ -28,6 +30,7 @@ public partial class AdventureResourceInspector : Node
private TreeItem root;
private TreeItem initialData;
private TreeItem seedpacketData;
public override void _Ready()
{
@ -48,6 +51,7 @@ public partial class AdventureResourceInspector : Node
root = CreateItem(LEVEL_ITEM_NAME);
initialData = CreateItem(INITIAL_ITEM_NAME, root);
seedpacketData = CreateItem(SEEDPACKETS_ITEM_NAME, root);
for (int i = 0; i < heldResource.waves.Count; i++)
{
@ -58,7 +62,7 @@ public partial class AdventureResourceInspector : Node
CreateItem(EVENTS_ITEM_NAME, wave);
CreateItem(HUGEWAVE_ITEM_NAME, TreeItem.TreeCellMode.Check, true, wave)
.SetChecked(0, heldResource.waves[i].isHugeWave);
var delay = tree.CreateItem(wave);
if (heldResource.waves[i].customWaveDelay > 0)
@ -94,8 +98,7 @@ public partial class AdventureResourceInspector : Node
var editor = zombieEditorScene.Instantiate<ZombieEditor>();
editorContainer.AddChild(editor);
editor.SetEditedWave(heldResource.waves[GetWaveIndex(selected.GetParent())]);
editor.SaveCallback += adventureEditor.Save;
SetupWaveEditor(editor, heldResource.waves[GetWaveIndex(selected.GetParent())]);
return;
case EVENTS_ITEM_NAME:
@ -103,9 +106,14 @@ public partial class AdventureResourceInspector : Node
case INITIAL_ITEM_NAME:
var initialEditor = initialEditorScene.Instantiate<InitialEditor>();
editorContainer.AddChild(initialEditor);
initialEditor.SetData(heldResource);
initialEditor.SaveCallback += adventureEditor.Save;
SetupEditor(initialEditor);
break;
case SEEDPACKETS_ITEM_NAME:
var seedpacketEditor = seedpacketEditorScene.Instantiate<SeedpacketEditor>();
editorContainer.AddChild(seedpacketEditor);
SetupEditor(seedpacketEditor);
break;
}
}
@ -161,10 +169,21 @@ public partial class AdventureResourceInspector : Node
private TreeItem CreateItem(string Name, TreeItem.TreeCellMode cellMode, bool editable, TreeItem root = null)
{
var item = tree.CreateItem(root);
item.SetCellMode(0,cellMode);
item.SetCellMode(0, cellMode);
item.SetEditable(0, editable);
item.SetText(0, Name);
return item;
}
private void SetupEditor(BaseEditor editor)
{
editor.SetEditedData(heldResource);
editor.SaveCallback += adventureEditor.Save;
}
private void SetupWaveEditor(BaseWaveEditor editor, WaveData editedWave)
{
SetupEditor(editor);
editor.SetEditedWave(editedWave);
}
}
#endif

View file

@ -0,0 +1,51 @@
using Godot;
using Newlon.Resources;
[Tool]
public partial class DnDSeedpacket : TextureButton
{
[Signal] public delegate void SaveCallbackEventHandler();
[Export] private TextureRect preview;
public PlantResource HeldResource;
public override bool _CanDropData(Vector2 atPosition, Variant data)
{
if (data.VariantType == Variant.Type.Dictionary)
{
if ((string)data.AsGodotDictionary()["type"] == "files")
{
return ResourceLoader.Load(data.AsGodotDictionary()["files"].AsGodotArray<string>()[0]) is PlantResource;
}
}
return false;
}
public override void _DropData(Vector2 atPosition, Variant data)
{
HeldResource = ResourceLoader.Load(data.AsGodotDictionary()["files"].AsGodotArray<string>()[0]) as PlantResource;
Update();
}
public override void _Pressed()
{
HeldResource = null;
Update();
}
private void Update()
{
RefreshTexture();
EmitSignal(SignalName.SaveCallback);
}
public void RefreshTexture()
{
if (HeldResource != null)
{
preview.Texture = HeldResource.Preview;
}
else
{
preview.Texture = null;
}
}
}

View file

@ -0,0 +1 @@
uid://bhah157u6q56b

View file

@ -0,0 +1,53 @@
using Godot;
using Godot.Collections;
using Newlon.Resources;
[Tool]
public partial class SeedpacketEditor : BaseEditor
{
private const string PLANTS_DIRECTORY = "res://assets/plants/";
public override void SetEditedData(AdventureLevelResource data)
{
base.SetEditedData(data);
SetPrepickedPlants();
}
public override void Save()
{
CalculatePrepickedPlants();
base.Save();
}
private void SetPrepickedPlants()
{
for (int i = 0; i < editedResource.prepickedPlants.Count; i++)
{
if (GetNode("%PrepickedContainer").GetChild(i).GetNode("Seedpacket") is DnDSeedpacket packet)
{
packet.HeldResource = TryGetPlant(editedResource.prepickedPlants[i]);
packet.RefreshTexture();
}
}
}
private void CalculatePrepickedPlants()
{
Array<string> prepicked = new();
foreach (var child in GetNode("%PrepickedContainer").GetChildren())
{
if (child.GetNode("Seedpacket") is DnDSeedpacket packet && packet.HeldResource != null)
{
prepicked.Add(packet.HeldResource.GetInternalID());
}
}
editedResource.prepickedPlants = prepicked;
}
private PlantResource TryGetPlant(string plantName)
{
foreach (var file in ResourceLoader.ListDirectory(PLANTS_DIRECTORY))
{
if (plantName != file.TrimSuffix(".tres").ToLower()) continue;
return ResourceLoader.Load<PlantResource>(PLANTS_DIRECTORY + file);
}
return null;
}
}

View file

@ -0,0 +1 @@
uid://d1ks2q0c3eu0v

View file

@ -0,0 +1,28 @@
@tool
extends TextureButton
signal save_callback
var held_data : PlantResource = null
@export var preview : TextureRect
func _can_drop_data(at_position: Vector2, data: Variant) -> bool:
if typeof(data) == TYPE_DICTIONARY:
if data.type == "files":
return load(data.files[0]) is PlantResource
return false
func _drop_data(at_position: Vector2, data: Variant) -> void:
held_data = load(data.files[0]) as PlantResource
update()
func update():
if held_data:
preview.texture = held_data.Preview
else:
preview.texture = null
save_callback.emit()
func _pressed() -> void:
held_data = null
update()

View file

@ -0,0 +1 @@
uid://donugf6vnchij

View file

@ -2,19 +2,13 @@ using Godot;
[Tool]
public partial class ZombieEditor : VBoxContainer
public partial class ZombieEditor : BaseWaveEditor
{
public WaveData editedWave;
[Export] private ZE_GridContainer container;
[Signal] public delegate void SaveCallbackEventHandler();
public void SetEditedWave(WaveData data)
public override void SetEditedWave(WaveData data)
{
editedWave = data;
container.SetData(editedWave);
}
public void Save()
{
EmitSignal(SignalName.SaveCallback);
}
}