Nach langem hin und her habe ich für mich eine Lösung gefunden, welche vielleicht nicht unbedingt die beste Wahl ist, wenn man viele Mods verwendet, aber sie funktioniert und ist relativ simpel. Kurz gesagt, ich erweite einfach die vorhandenen Rezepte und deren Verwaltung durch optionale Werte. Damit kann ich die Vorteile der normalen Rezepte weiterhin nutzen ohne Probleme mit bereits vorhandenen Rezepten zu haben und ich brauche die ganzen Prüfungen nicht erneut machen. Meine Einschätzung der Vor- & Nachteile dieser Lösung:
+ einfacher Aufbau
+ erweitert die Rezepte
+ man kann die Animationen mit ändern
+ beliebige Anzahl an "Zutaten" möglich
+ mehrere Rezepte pro Objekt möglich
+ Logik bleibt in den Rezepten
- Wahrscheinlichkeit der Unverträglichkeit bei der Verwendung mehrerer Mods
- Hauptklassen werden erweitert
RecipeBase
modded class RecipeBase
{
int m_CommandUID;
int m_StanceMask;
bool m_HideItemInHands;
bool HasCustomCommandUID()
{
if(m_CommandUID)
{
return true;
}
return false;
}
bool HasCustomStanceMask()
{
if(m_StanceMask)
{
return true;
}
return false;
}
int GetCustomCommandUID()
{
return m_CommandUID;
}
int GetCustomStanceMask()
{
return m_StanceMask;
}
bool GetHideItemInHands()
{
if(!m_HideItemInHands)
{
return false;
}
return true;
}
}
Alles anzeigen
PluginRecipesManager
modded class PluginRecipesManager extends PluginRecipesManagerBase
{
bool RecipeHasCustomCommandUID(int recipe_id)
{
if(m_RecipeList[recipe_id])
{
return m_RecipeList[recipe_id].HasCustomCommandUID();
}
return false;
}
bool RecipeHasCustomStanceMask(int recipe_id)
{
if(m_RecipeList[recipe_id])
{
return m_RecipeList[recipe_id].HasCustomStanceMask();
}
return false;
}
bool RecipeGetHideItemInHands(int recipe_id)
{
if(m_RecipeList[recipe_id])
{
return m_RecipeList[recipe_id].GetHideItemInHands();
}
return true;
}
int RecipeGetCustomCommandUID(int recipe_id)
{
return m_RecipeList[recipe_id].GetCustomCommandUID();
}
int RecipeGetCustomStanceMask(int recipe_id)
{
return m_RecipeList[recipe_id].GetCustomStanceMask();
}
}
Alles anzeigen
ActionWorldCraft
modded class ActionWorldCraft: ActionContinuousBase
{
bool m_HideItemInHands = true;
override bool SetupAction(PlayerBase player, ActionTarget target, ItemBase item, out ActionData action_data, Param extra_data = NULL)
{
if(!super.SetupAction(player, target, item, action_data, extra_data))
{
return false;
}
if(GetGame().IsClient() || !GetGame().IsMultiplayer())
{
WorldCraftActionData action_data_wc;
PluginRecipesManager module_recipes_manager;
Class.CastTo(action_data_wc, action_data);
Class.CastTo(module_recipes_manager, GetPlugin(PluginRecipesManager));
action_data_wc.m_RecipeID = action_data.m_Player.GetCraftingRecipeID();
if(module_recipes_manager)
{
if(module_recipes_manager.RecipeHasCustomCommandUID(action_data_wc.m_RecipeID))
{
m_CommandUID = module_recipes_manager.RecipeGetCustomCommandUID(action_data_wc.m_RecipeID);
}
if(module_recipes_manager.RecipeHasCustomStanceMask(action_data_wc.m_RecipeID))
{
m_StanceMask = module_recipes_manager.RecipeGetCustomStanceMask(action_data_wc.m_RecipeID);
}
m_HideItemInHands = module_recipes_manager.RecipeGetHideItemInHands(action_data_wc.m_RecipeID);
}
}
return true;
}
override void Start(ActionData action_data)
{
super.Start(action_data);
if(action_data.m_Player)
{
action_data.m_Player.GetItemAccessor().HideItemInHands(m_HideItemInHands);
}
}
}
Alles anzeigen
Mein Rezept zur Herstellung von Nägeln am Amboss mit Hilfe eines Hammers
class SmithNails extends RecipeBase
{
string m_AnvilIngredient;
int m_AnvilIngredientQuantity;
override void Init()
{
m_Name = "#smithnails";
m_IsInstaRecipe = false;//should this recipe be performed instantly without animation
m_Specialty = UASoftSkillsWeight.ROUGH_HIGH;// value > 0 for roughness, value < 0 for precision
m_CommandUID = DayZPlayerConstants.CMD_ACTIONFB_DISASSEMBLE;
m_StanceMask = DayZPlayerConstants.STANCEMASK_ERECT;
m_HideItemInHands = false;
//conditions
m_MinDamageIngredient[0] = -1;//-1 = disable check
m_MaxDamageIngredient[0] = 3;//-1 = disable check
m_MinQuantityIngredient[0] = 1;//-1 = disable check
m_MaxQuantityIngredient[0] = -1;//-1 = disable check
m_MinDamageIngredient[1] = -1;//-1 = disable check
m_MaxDamageIngredient[1] = 3;//-1 = disable check
m_MinQuantityIngredient[1] = -1;//-1 = disable check
m_MaxQuantityIngredient[1] = -1;//-1 = disable check
//----------------------------------------------------------------------------------------------------------------------
//INGREDIENTS
//ingredient 1
InsertIngredient(0,"Hammer");//you can insert multiple ingredients this way
m_IngredientAddHealth[0] = -10;// 0 = do nothing
m_IngredientSetHealth[0] = -1; // -1 = do nothing
m_IngredientAddQuantity[0] = 0;// 0 = do nothing
m_IngredientDestroy[0] = false;//true = destroy, false = do nothing
m_IngredientUseSoftSkills[0] = false;// set 'true' to allow modification of the values by softskills on this ingredient
//ingredient 2
InsertIngredient(1,"Anvil");//you can insert multiple ingredients this way
m_IngredientAddHealth[1] = -5;// 0 = do nothing
m_IngredientSetHealth[1] = -1; // -1 = do nothing
m_IngredientAddQuantity[1] = 0;// 0 = do nothing
m_IngredientDestroy[1] = false;// false = do nothing
m_IngredientUseSoftSkills[1] = true;// set 'true' to allow modification of the values by softskills on this ingredient
//Anvil Ingredient
m_AnvilIngredient = "IronIngot";
m_AnvilIngredientQuantity = 100;
//----------------------------------------------------------------------------------------------------------------------
//result1
AddResult("Nail");//add results here
m_ResultSetFullQuantity[0] = false;//true = set full quantity, false = do nothing
m_ResultSetQuantity[0] = 10;//-1 = do nothing
m_ResultSetHealth[0] = -1;//-1 = do nothing
m_ResultInheritsHealth[0] = 0;// (value) == -1 means do nothing; a (value) >= 0 means this result will inherit health from ingredient number (value);(value) == -2 means this result will inherit health from all ingredients averaged(result_health = combined_health_of_ingredients / number_of_ingredients)
m_ResultInheritsColor[0] = -1;// (value) == -1 means do nothing; a (value) >= 0 means this result classname will be a composite of the name provided in AddResult method and config value "color" of ingredient (value)
m_ResultToInventory[0] = -2;//(value) == -2 spawn result on the ground;(value) == -1 place anywhere in the players inventory, (value) >= 0 means switch position with ingredient number(value)
m_ResultUseSoftSkills[0] = false;// set 'true' to allow modification of the values by softskills on this result
m_ResultReplacesIngredient[0] = -1;// value == -1 means do nothing; a value >= 0 means this result will transfer item propertiesvariables, attachments etc.. from an ingredient value
}
override float GetLengthInSecs()
{
return UATimeSpent.SMITH_NAILS_TIME;
}
override bool CanDo(ItemBase ingredients[], PlayerBase player)//final check for recipe's validity
{
Anvil anvil;
ItemBase tool_in_hand = ItemBase.Cast(player.GetHumanInventory().GetEntityInHands());
Class.CastTo(anvil, ingredients[1]);
// Anvil must be on the ground
if(tool_in_hand == ingredients[1])
{
return false;
}
if(anvil.GetQuantitySumOfIngotType(m_AnvilIngredient) < m_AnvilIngredientQuantity)
{
return false;
}
return true;
}
override void Do(ItemBase ingredients[], PlayerBase player,array<ItemBase> results, float specialty_weight)//gets called upon recipe's completion
{
Anvil anvil;
array<ItemBase> ingots;
int quantity_remaining = m_AnvilIngredientQuantity;
int ingot_quantity;
Class.CastTo(anvil, ingredients[1]);
ingots = anvil.GetIngotsFromAttachment(m_AnvilIngredient);;
foreach(ItemBase ingot: ingots)
{
ingot_quantity = ingot.GetQuantity();
if(ingot_quantity >= quantity_remaining)
{
ingot.SetQuantity(ingot_quantity - quantity_remaining);
Print("[DoItYourself][SmithNails][Do] " + ingot.GetType() + " remains " + ingot.GetQuantity());
break;
}
else
{
ingot.SetQuantity(0);
quantity_remaining -= ingot_quantity;
Print("[DoItYourself][SmithNails][Do] " + ingot.GetType() + " destroyed - Recipe remains " + quantity_remaining);
}
}
}
};
Alles anzeigen
Um das Rezept kurz zu erklären:
Die "Zutaten" sind ein Hammer und ein Amboss. Mit m_AnvilIngredient gebe ich den benötigten Barren an, welcher im Amboss als Attachment hinterlegt sein muss. Außerdem wird durch m_AnvilIngredientQuantity eine Restmenge des Barrens benötigt, wobei es in dem Fall unerheblich ist ob es ein Barren ist oder mehrere vorhanden sind. Der Amboss kann bis zu 5 Barren fassen. Die Variablen m_CommandUID und m_StanceMask sollten von den Actions bereits bekannt sein. Ich verwende hier die selben Namen um Rückschluss auf deren Bedeutung zu geben. Ein Name für alles ist sehr hilfreich. Neu ist m_HideItemInHands, wobei der Name schon sagt was es bedeutet, ob das Tool in den Händen bei der Animation angezeigt wird oder nicht. Die Animationen sind da manchmal sehr speziell und blockieren die gesamte Handlung, daher ist der Wert wichtig.
Funktioniert soweit richtig gut. Die Grundlagen der Rezepte prüfen die Voraussetzungen selbstständig, ich habe sozusagen diese Prüfungen nur erweitert. Die Klasse des Amboss habe ich jetzt erstmal außen vor gelassen, da dort nur Prüfungen vorgenommen und ein paar Werte geliefert werden.
Mit dem ganzen kann ich jetzt multiple Rezepte an Objekte binden, mehr Zutaten zulassen und die Animationen ändern, ohne weitere Klassen anlegen zu müssen. Ist nur ein funktionierender Prototyp, muss noch umfangreich getestet werden. Sicherlich fehlen noch einige Sicherungen, z.B. das blockieren der Attachments im Amboss, ansonsten kann man diese einfach während der Animation entfernen. Auch kann es sein das man ggf. noch Variablen synchronisieren muss. Lokal funktioniert dies so aber erstmal.
Was meint ihr dazu? Ideen, Ergänzungen, Kritik?