| 08-24-2008, 03:04 PM | #1 | |
Yes, it's true. Yet another one.
RecipeSYS v0.6d RecipeSYS is a system that allows you to have recipes that combine two or more (up to six) items into one item. The code has a rather good documentation on how to use it, and the map also contains an example trigger of usage in GUI. All you need to do is add one line of Jass for each recipe you want, and the system will do the rest. The system can even be used for stacking charged items (not the easiest way of doing that, though, as you would need one line for every item that can stack). Features Requirements A vJass compiler (NewGen includes one). Table by Vexorian. The Code C++:library RecipeSYS initializer Init uses Table // ¤ v0.6d ¤ // ( *'*-._.-*'*-._.-*'*-._.-*'* ) // ) RecipeSYS ( // ( Created by Artificial ) // )*'*-._.-*'*-._.-*'*-._.-*'*( // ¤ ¤ // // How to use the RecipeSYS // ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ // ---- Adding recipes // Adding recipes is rather easy. You just call a function // and give it some arguments. The function you call is // recipe.create, and is called like this: // // call recipe.create(i1, i2, i3, i4, i5, i6, result, sfx, attPoint, charges, chargeType) // // i1 - i6 are the raw codes* of the items required for the // recipe to combine. result is the raw code of the item they // will combine to. sfx is the path of the special effect you // want to use (give "" for default), and attPoint the attachment // point of it ("" for default). The boolean charges is whether // the result should have some other amount of charges than the // default one. If it is true, chargeType determines what amount // of charges the result will get when combined (-1 => amount of // charges left in the ingredient with most charges, 0 => sum of // charges left in the ingredients, anything else => the number // given as the argument). // // * You can find out the rawcodes by going to the object // editor and pressing ctrl + D. The first 4 characters // are the rawcode of the item. When calling the function, // remember to put the rawcode between ' and ' in case // you want it to work. // // If you want the recipe to require less than 6 items, just give // zeros as ingredient arguments. // // --- AddRecipe Wrappers // You can also add recipes using some of the wrapper // functions: AddRecipe, AddRecipeEx, AddRecipeWithCharges, // and AddRecipeWithChargesEx. // // AddRecipe takes i1, i2, i3, i4, i5, i6, result // AddRecipeEx takes i1, i2, i3, i4, i5, i6, result, sfx, attPoint // AddRecipeWithCharges takes i1, i2, i3, i4, i5, i6, result, chargeType // AddRecipeWithChargesEx takes i1, i2, i3, i4, i5, i6, result, chargeType, sfx, attPoint // // ---- Removing Recipes // There are two ways of removing recipes: destroyin a specific // recipe and removing recipes by the result (removes all recipes // with that item as result). // Removing a specific recipe is done by calling the .destroy method // for that recipe, and removing by result is done by using the // RemoveRecipeByResult function, eg. like this: // // call RemoveRecipeByResult('belv') // // ---- Disassembling Items // Disassembling an item that is a result of some recipe would cause // the item to be replaced with the ingredients of the recipe. // Example of usage: // // call DisassembleItem(GetManipulatedItem(), GetTriggerUnit()) // // The first argument is the item to be disassembled and the second // one is the unit to give the ingredients to. In case you don't want // to give the items to an unit, give null as the unit argument. // You also have the DisassembleItemByRecipe function, which takes // one argument more: the recipe whose ingredients you want the item // to be disassembled to. // // There are a few restrictions with the disassembling: // - If the item being disassemled isn't created by the system, // and used on an item that is the result of several recipes // the system will just give the items that are required for one // of the recipes. // - When used on an recipe added via the charged recipe thingy // the ingredient items won't recieve the amount of items they // had when the result was made, but the default amount of charges. // // Note: If you are using the function with the 'A unit Loses an item' // event you'll need to add a little wait before the function // call in case you want the items to be created at the position // where the item was dropped. And the wait is also needed when // the item being disassembled is the result of a recipe that has // only the same type of items as ingredients (or at least I think so). // // ---- Disabling and Re-Enabling Recipes // Instead of removing a recipe to disable it and then adding the // recipe again you can also disable and enable the recipe. // This is done by setting the enabled member of the recipe to false // (or to true if enabling). You can also use the EnableRecipeByResult // function: // // call EnableRecipeByResult('fgdg', false) // // That would disable the recipes that have the item 'fgdg' as result. // The enabling of the recipe would happen with the same function, but // with true as the boolean argument. // // ---- Disabling/Re-enabling the System // If you need to disable/enable the system for some time, you can use these lines: // // call DisableTrigger(RecipeSYS_TRIGGER) // call EnableTrigger(RecipeSYS_TRIGGER) // // Note, that this only disables the combining of items by the system itself, // if you're using a combining trigger of your own, you'll need to disable that // trigger. // // ---- Manual Checking For Recipes // In case you'd want to use some other event than the 'A unit Acquires an // item', you can set AUTO_COMBINE to false, and create a trigger that has // the event you want (eg. 'A unit Starts the effect of an ability'), and // then call the CheckForRecipes function from there. The arguments it takes // are the item that should be checked if it belongs to a recipe and the unit // the result should be created to (if any is created). // The function returns a boolean depending on whether it combined the item // to something or not. And if it combined something, you can refer to the // created item with bj_lastCreatedItem (Last created item in GUI). // // Strengths of RecipeSYS // ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ // - Supports having several items of the same type as // ingredients in the same recipe. // - Supports having the same item type as an ingredient in // several recipes. // - Allows to specify the special effect and it's attachment // point (each recipe can have its own ones, if you wish so). // - All you need to do is add the recipes. // - You can remove recipes. // - You can add recipes with results that have charges. // - The amount of charges can be predefined, the sum of charges // left in the ingredients, or the amount of charges in the // ingredient with most charges. // - You can disable and enable single recipes or the whole sytem. // - You can disassemble items. // - You can disable the automatic combining of items, and create // a trigger that combines items manually (so you can have any // event you want). // // Weaknesses of RecipeSYS // ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ // - Don't know if it's optimized as much as it could nor if it's // the best recipe system out there. ^_^ // - The item disassembling has some restrictions, and doesn't work // flawlessy with the 'A unit Loses an item' event (see the Test2 // trigger in the demo map or the instructions of the function for // additional information). // - The max amount of item types you can use in recipes as // ingredients is 8190 / AMOUNT_ING and as results 8190 / AMOUNT_RES. // // How to import RecipeSYS // ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ // Two easy steps: // - Copy this trigger to your map. // - Copy the trigger 'Table' to your map. // Alternatively: // - Create a trigger named 'RecipeSYS' in your map. // - Convert it to Jass (Custom Script) and replace all // of the code in there with the code in this trigger. // - Create a trigger named 'Table' in your map. // - Convert it to Jass (Custom Script) and replace all // of the code in there with the code in the trigger 'Table'. globals // ¤ ¤ // ( *'*-._.-*'*-._.-*'*-._.-*'* ) // ) RecipeSYS configuration ( // ( *'*-._.-*'*-._.-*'*-._.-*'* ) // ¤ ¤ private constant boolean AUTO_COMBINE = true //Whether you want the system to automatically combine //the ingredients of a recipe to the result when a unit //has all of them. private constant string SFX_PATH = "Abilities\\Spells\\Items\\TomeOfRetraining\\TomeOfRetrainingCaster.mdl" //The path of the default effect. private constant string SFX_POINT = "origin" //The default attachment point. private constant integer AMOUNT_ING = 10 //The amount of recipes an item can be an ingredient in. private constant integer AMOUNT_RES = 10 //The amount of recipes an item can be a result in. // ¤ ¤ // ( *'*-._.-*'*-._.-*'*-._.-*'* ) // )DO NOT EDIT PAST THIS POINT( // ( *'*-._.-*'*-._.-*'*-._.-*'* ) // )Well, you can if you really( // ( want to, but only if you ) // )know what you're doing. And( // ( it's not needed, anyways. ) // )*'*-._.-*'*-._.-*'*-._.-*'*( // ¤ ¤ public constant trigger TRIGGER = CreateTrigger() private Table ING_TABLE private Table RES_TABLE private HandleTable COMBINE_TABLE endglobals private type ingIn extends recipe array [AMOUNT_ING] private type resIn extends recipe array [AMOUNT_RES] struct recipe integer array items [6] integer result integer chargeType string sfx string point boolean resultHasCharges boolean enabled static method create takes integer i1, integer i2, integer i3, integer i4, integer i5, integer i6, integer result, string sfx, string attPoint, boolean charges, integer chargetype returns recipe local recipe i = recipe.allocate() local ingIn ing local resIn res local boolean array b local integer j = 0 local integer k local integer l = 0 set i.items[0] = i1 set i.items[1] = i2 set i.items[2] = i3 set i.items[3] = i4 set i.items[4] = i5 set i.items[5] = i6 set i.result = result set i.enabled = true set i.resultHasCharges = charges set i.chargeType = chargetype //To prevent linking the recipe to the item type twice. set b[0] = true set b[1] = i2 != i1 set b[2] = i3 != i2 and i3 != i1 set b[3] = i4 != i3 and i4 != i2 and i4 != i1 set b[4] = i5 != i4 and i5 != i3 and i5 != i2 and i5 != i1 set b[5] = i6 != i5 and i6 != i4 and i6 != i3 and i6 != i2 and i6 != i1 //Set the SFX things (default or specified). if sfx == "" then set i.sfx = SFX_PATH else set i.sfx = sfx endif if attPoint == "" then set i.point = SFX_POINT else set i.point = attPoint endif //Linking the recipe to the item types. loop if i.items[j] != 0 and b[j] then set k = ING_TABLE[i.items[j]] if k != 0 then //Item type is in another recipe aswell. set ing = ingIn(k) set k = 0 //Seek for an open slot. loop exitwhen ing[k] == 0 set k = k + 1 if k == ingIn.size then debug call BJDebugMsg("|cffff0202RecipeSYS Error:|r AMOUNT_ING is too small!") return 0 endif endloop else //First appearance for the item type. set ing = ingIn.create() set k = 0 endif set ing[k] = i set ING_TABLE[i.items[j]] = integer(ing) endif set j = j + 1 exitwhen j == 6 endloop set k = RES_TABLE[i.result] if k != 0 then //Item type is in some other recipe, too. set res = resIn(k) set k = 0 loop exitwhen res[k] == 0 set k = k + 1 if k == resIn.size then debug call BJDebugMsg("|cffff0202RecipeSYS Error:|r AMOUNT_RES too small!") return 0 endif endloop else //First time being in a recipe for the item type. set res = resIn.create() endif set res[k] = i set RES_TABLE[i.result] = integer(res) return i endmethod private method ClearRecipeFromIngredient takes integer it returns nothing local integer i = 0 local integer j local ingIn ing = ingIn(ING_TABLE[it]) if it == 0 or integer(ing[0]) == 0 then return endif //Finding the right array slot and setting it's value to 0. loop exitwhen i == ingIn.size if ing[i] == this then set j = i + 1 //Finding the last used array slot. loop exitwhen j == ingIn.size or ing[j] == 0 set j = j + 1 endloop set j = j - 1 set ing[i] = ing[j] set ing[j] = 0 exitwhen true endif set i = i + 1 endloop //Free the array and flush if the slots are empty. if integer(ing[0]) == 0 then call ING_TABLE.flush(it) call ing.destroy() endif endmethod private method ClearRecipeFromResult takes integer it returns nothing local integer i = 0 local integer j local resIn res = resIn(RES_TABLE[it]) if it == 0 then return endif //Finding the right array slot and setting it's value to 0. loop exitwhen i == resIn.size if res[i] == this then set j = i + 1 //Finding the last used array slot. loop exitwhen j == resIn.size or res[j] == 0 set j = j + 1 endloop set j = j - 1 set res[i] = res[j] set res[j] = 0 exitwhen true endif set i = i + 1 endloop //Free the array slots and flush if it's empty. if res[0] == 0 then call RES_TABLE.flush(it) call res.destroy() endif endmethod method onDestroy takes nothing returns nothing local integer i = 0 loop call .ClearRecipeFromIngredient(.items[i]) set i = i + 1 exitwhen i == 6 endloop call .ClearRecipeFromResult(.result) set .result = 0 endmethod endstruct //**************************************************** //** Recipes Without Charges ** //**************************************************** function AddRecipe takes integer item1, integer item2, integer item3, integer item4, integer item5, integer item6, integer result returns recipe return recipe.create(item1, item2, item3, item4, item5, item6, result, "", "", false, 0) endfunction function AddRecipeEx takes integer item1, integer item2, integer item3, integer item4, integer item5, integer item6, integer result, string sfx, string attachmentPoint returns recipe return recipe.create(item1, item2, item3, item4, item5, item6, result, sfx, attachmentPoint, false, 0) endfunction //**************************************************** //** Recipes With Charges ** //**************************************************** function AddRecipeWithCharges takes integer item1, integer item2, integer item3, integer item4, integer item5, integer item6, integer result, integer chargeType returns recipe return recipe.create(item1, item2, item3, item4, item5, item6, result, "", "", true, chargeType) endfunction function AddRecipeWithChargesEx takes integer item1, integer item2, integer item3, integer item4, integer item5, integer item6, integer result, integer chargeType, string sfx, string attachmentPoint returns recipe return recipe.create(item1, item2, item3, item4, item5, item6, result, sfx, attachmentPoint, true, chargeType) endfunction //**************************************************** //** Removing Recipes ** //**************************************************** function RemoveRecipeByResult takes integer result returns nothing local resIn res = resIn(RES_TABLE[result]) loop exitwhen integer(res[0]) == 0 call res[0].destroy() endloop endfunction //**************************************************** //** Disabling and enabling recipes ** //**************************************************** function EnableRecipeByResult takes integer result, boolean enable returns nothing local resIn res = resIn(RES_TABLE[result]) local integer i = 0 loop exitwhen integer(res[i]) == 0 set res[i].enabled = enable set i = i + 1 endloop endfunction //**************************************************** //** Disassembling Combined Items ** //**************************************************** function DisassembleItemByRecipe takes item whichItem, unit whichUnit, recipe re returns nothing local integer i = 0 local real x = GetItemX(whichItem) local real y = GetItemY(whichItem) local boolean b = IsTriggerEnabled(GetTriggeringTrigger()) local boolean c = IsTriggerEnabled(TRIGGER) if re.result == GetItemTypeId(whichItem) then if b then //Avoid clashing with some events. call DisableTrigger(GetTriggeringTrigger()) endif call COMBINE_TABLE.flush(whichItem) call RemoveItem(whichItem) //Should the items be created for a unit or at ground? if whichUnit == null then loop call CreateItem(re.items[i], x, y) set i = i + 1 exitwhen i == 6 endloop else if c then //Preventing infinite loop. call DisableTrigger(TRIGGER) endif loop call UnitAddItemById(whichUnit, re.items[i]) set i = i + 1 exitwhen i == 6 endloop if c then call EnableTrigger(TRIGGER) endif endif if b then call EnableTrigger(GetTriggeringTrigger()) endif endif endfunction function DisassembleItem takes item whichItem, unit whichUnit returns nothing local integer id = GetItemTypeId(whichItem) local resIn r = resIn(RES_TABLE[id]) local recipe re = recipe(COMBINE_TABLE[whichItem]) if integer(re) == 0 or re.result != id then //The last one just in case the recipe has been destroyed. if integer(r[0]) == 0 then return endif set re = r[0] endif call DisassembleItemByRecipe(whichItem, whichUnit, re) endfunction //**************************************************** //** Combining ** //**************************************************** private function Combine takes recipe rec, unit u returns boolean local integer array itemsReq local integer itemInSlot local integer topCharges = 0 local integer sumCharges = 0 local integer i = 0 local integer j = 0 local item resu local item array itemsToCombine //Setting the items. loop set itemsReq[i] = rec.items[i] set i = i + 1 exitwhen i == 6 endloop set i = 0 //Finding the items. loop set itemInSlot = GetItemTypeId(UnitItemInSlot(u, i)) loop if itemsReq[j] == itemInSlot and itemInSlot != 0 then set itemsToCombine[j] = UnitItemInSlot(u, i) set itemsReq[j] = 0 exitwhen true endif set j = j + 1 exitwhen j == 6 endloop set j = 0 set i = i + 1 exitwhen i == 6 endloop set i = 0 set j = 0 //Checking if all items were found. loop if itemsReq[i] != 0 then loop set itemsToCombine[j] = null set j = j + 1 exitwhen j == 6 endloop return false endif set i = i + 1 exitwhen i == 6 endloop set i = 0 //Remove the old items. loop //Set the different charge amounts in case the result has charges. set j = GetItemCharges(itemsToCombine[i]) set sumCharges = sumCharges + j if j > topCharges then set topCharges = j endif call COMBINE_TABLE.flush(itemsToCombine[i]) call RemoveItem(itemsToCombine[i]) set itemsToCombine[i] = null set i = i + 1 exitwhen i == 6 endloop //Create the result. set resu = UnitAddItemById(u, rec.result) call DestroyEffect(AddSpecialEffectTarget(rec.sfx, u, rec.point)) //Set charges if it should have any. if rec.resultHasCharges then if rec.chargeType == 0 then call SetItemCharges(resu, sumCharges) elseif rec.chargeType == -1 then call SetItemCharges(resu, topCharges) else call SetItemCharges(resu, rec.chargeType) endif endif //Set the data if wanted. set COMBINE_TABLE[resu] = integer(rec) set bj_lastCreatedItem = resu set resu = null return true endfunction //**************************************************** //** Recipe Finding ** //**************************************************** function CheckForRecipes takes item check, unit u returns boolean local ingIn r = ingIn(ING_TABLE[GetItemTypeId(check)]) local integer i = 0 loop exitwhen integer(r[i]) == 0 if r[i].enabled then if Combine(r[i], u) then return true endif endif set i = i + 1 endloop return false endfunction private function Check takes nothing returns boolean return CheckForRecipes(GetManipulatedItem(), GetTriggerUnit()) endfunction //===================================================================== private function SafeFilt takes nothing returns boolean return true endfunction //===================================================================== private function Init takes nothing returns nothing local integer index = 0 if AUTO_COMBINE then loop call TriggerRegisterPlayerUnitEvent(TRIGGER, Player(index), EVENT_PLAYER_UNIT_PICKUP_ITEM, Filter(function SafeFilt)) set index = index + 1 exitwhen index == bj_MAX_PLAYER_SLOTS endloop call TriggerAddCondition(TRIGGER, Condition(function Check)) endif set ING_TABLE = Table.create() set RES_TABLE = Table.create() set COMBINE_TABLE = HandleTable.create() endfunction endlibrary Example of Usage Trigger: T
![]() Conditions
![]() Actions
![]() ![]() Custom script: local recipe re = AddRecipe('rde2', 'rde2', 0, 0, 0, 0, 'belv')
![]() ![]() Custom script: call AddRecipe('rde1', 'rde2', 0, 0, 0, 0, 'belv')
![]() ![]() Custom script: call AddRecipeWithCharges('fgdg', 'fgdg', 0, 0, 0, 0, 'fgdg', 0)
![]() ![]() Set Item = Boots of Quel'Thalas +6 0028 <gen>
![]() ![]() Custom script: call DisassembleItemByRecipe(udg_Item, null, re)
![]() ![]() Custom script: call EnableRecipeByResult('belv', false)
![]() ![]() Wait 10.00 seconds
![]() ![]() Game - Display to (All players) the text: Enabling.
![]() ![]() Custom script: call EnableRecipeByResult('belv', true)
![]() ![]() Wait 10.00 seconds
![]() ![]() Game - Display to (All players) the text: Destroying.
![]() ![]() Custom script: call RemoveRecipeByResult('belv')Importing Copy the trigger called RecipeSYS from the attached map or create a trigger named RecipeSYS, convert it to custom text, and replace everything inside it with the code above. Q&A Q: There are lots of recipe systems already. Why on earth did you make another one?! A: I felt like it. Duh... Q: How is this different from the other systems? ![]() A: Well, I didn't make the other ones (although you might think I did (even though you've never heard of me before)). You could also take a look at the feature list, it might have some differences. Q: The 'Features' list is like exactly the same as the 'Strengths' list in the comments! ![]() A: No shit, Sherlock. Q: Does the system have any weaknesses? ![]() A: Besides the ones mentioned at the end of the comment block, I don't know. You tell me. Q: Can I leave suggestions, questions, and/or comments? A: If they are somehow intelligent. Q: How many recipes can I have at once? A: Up to 1365. Q: I seriously think no more recipe systems are needed. A: Ok. Q: How do I use this system? A: Didn't you look at the code at all? The 4th row with text is 'How To Use RecipeSYS'. Could there be instructions for usage under that title? I doupt. :) Changelog
|
| 08-24-2008, 05:41 PM | #2 |
You could have made it much faster, right now, you need to loop through every single recipe in the game when a unit acquires an item, think about it, with only 6 items in a unit's inventory, there got to be a better way... |
| 08-24-2008, 06:31 PM | #3 |
I'm still rather new with Jass (excuses), and I'm having a hard time figuring out how to make it faster, although I know it probably could be done better. The only thing I can think of would be linking the recipes to the item types, which I don't know how to do. I guess the only way of doing that would be using gamecache. That should be faster, right? Maybe I'll need to learn to use gamecache, then. ![]() |
| 08-24-2008, 06:33 PM | #4 |
Arti, gc is slow. (I'm Vestras, from mapcrafting.com, in case you forgot your own site) |
| 08-24-2008, 06:58 PM | #5 |
gc is pretty fast as a two key hash table. Big arrays are faster, if they'll do what you need. |
| 08-24-2008, 07:18 PM | #6 |
> gc is slow I know it's somehow slow, but I guess it's faster than looping through every single recipe. And I know who you are, don't worry. ^_^ > Big arrays are faster, if they'll do what you need. I thought about arrays, but I can't figure out a way to transform the item's rawcode into a form that could be used as an array pointer. They are like WAY too big and vary too much. ![]() |
| 08-24-2008, 07:22 PM | #7 |
Why do item systems need to be fast anyway? They aren't being called by periodic timers or anything. Items should be, to quote TC, 'powerful'. |
| 08-24-2008, 08:51 PM | #8 |
Item systems don't need to be fast but this thing is a recipe system which will trigger everytime you pick up an item, anyway. Artificial: Yes, something like that would be good, another thing would be that in the case of a pickup event you only need to consider the recipes that use the item. GC is ok for this in terms of speed since it is O(1) instead of O(n) it would be faster, you could make your own hash table, but I think Griffen got a good idea with big arrays, it still though requires a way to convert the item type to an array index. The problem is how to implement this stuff without adding weight to the requirements, making it use its whole gamecache file would be a little too much. Also you'd have to be careful not to make this cause an item type limit. -you could use one of many libraries out there that do hashing- it wouldn't scale well with things like 50 recipes in the whole system, it seems like a big value but there isn't too much reason to use one of these systems if you don't plan having plenty of recipes in your map. -- The optimization would not be a requirement for approval, Something I don't like too much is how it forces the guy to use plain integers for the recipes thus losing some type safety and convenience around, you could actually make recipes creatable as just recipe.create() and what not, you can also make the functions return a recipe and make the recipe struct public and have some read only fields that could be helpful for the guy using your system. Even if you don't add these things, make the functions take and return recipe, it will make life easier when jasshelper gets type safety and that stuff. |
| 08-25-2008, 10:14 AM | #9 |
indent much? and what is 'cre8', i dont think i speak your language. Please speak english |
| 08-25-2008, 11:09 PM | #10 |
This isn't his thread anyways and I'll permit no thread-hijacking, so I've deleted that post. |
| 08-26-2008, 02:02 PM | #11 |
Ok, I made some improvements. First of all, I made the functions take and return recipes instead of integers, and the recipe struct no longer is private. Second of all, I made 2 versions of it; one using GC and one a hash table I found (this one). Now I'm wondering if you guys could tell me which one should be better, or if there is a way for me to test their speeds (which I would like to do even though you would be able to say which one is better) and how to do it. Here are the codes in case you wanna see them. Gamecache:library RecipeSYS initializer Init globals // ¤ ¤ // ( *'*-._.-*'*-._.-*'*-._.-*'* ) // ) RecipeSYS configuration ( // ( *'*-._.-*'*-._.-*'*-._.-*'* ) // ¤ ¤ private constant boolean AUTO_COMBINE = true //Whether you want the system to automatically combine //the ingredients of a recipe to the result when a unit //has all of them. private constant boolean USE_ITEM_DATA = true //Whether you allow the system to manipulate the //custom values of the items created by the system. private constant string SFX_PATH = "Abilities\\Spells\\Items\\TomeOfRetraining\\TomeOfRetrainingCaster.mdl" //The path of the default effect. private constant string SFX_POINT = "origin" //The default attachment point. private constant string GC_PATH = "RecipeSYS_gamecache.gc" // ¤ ¤ // ( *'*-._.-*'*-._.-*'*-._.-*'* ) // )DO NOT EDIT PAST THIS POINT( // ( *'*-._.-*'*-._.-*'*-._.-*'* ) // )Well, you can if you really( // ( want to, but only if you ) // )know what you're doing. And( // ( it's not needed, anyways. ) // )*'*-._.-*'*-._.-*'*-._.-*'*( // ¤ ¤ public constant trigger TRIGGER = CreateTrigger() private recipe array RECIPES private integer count = 0 endglobals type recipes extends integer array [50] struct recipe static gamecache gc integer array items [6] integer result integer chargeType string sfx string point boolean resultHasCharges boolean enabled static method create takes integer i1, integer i2, integer i3, integer i4, integer i5, integer i6, integer result, string sfx, string attPoint, boolean charges, integer chargetype returns recipe local recipe i = recipe.allocate() local boolean array b local integer j = 0 set i.items[0] = i1 set i.items[1] = i2 set i.items[2] = i3 set i.items[3] = i4 set i.items[4] = i5 set i.items[5] = i6 set i.result = result set i.enabled = true set i.resultHasCharges = charges set i.chargeType = chargetype set b[0] = true set b[1] = i2 != i1 set b[2] = i3 != i2 and i3 != i1 set b[3] = i4 != i3 and i4 != i2 and i4 != i1 set b[4] = i5 != i4 and i5 != i3 and i5 != i2 and i5 != i1 set b[5] = i6 != i5 and i6 != i4 and i6 != i3 and i6 != i2 and i6 != i1 if sfx == "" then set i.sfx = SFX_PATH else set i.sfx = sfx endif if attPoint == "" then set i.point = SFX_POINT else set i.point = attPoint endif loop if i.items[j] != 0 and b[j] then if HaveStoredString(.gc, "RecipeSYS", I2S(i.items[j])) then call StoreString(.gc, "RecipeSYS", I2S(i.items[j]), GetStoredString(.gc, "RecipeSYS", I2S(i.items[j])) + "|" + I2S(integer(i))) else call StoreString(.gc, "RecipeSYS", I2S(i.items[j]), I2S(integer(i))) endif endif set j = j + 1 exitwhen j == 6 endloop if HaveStoredString(.gc, "RecipeSYS_Result", I2S(i.result)) then call StoreString(.gc, "RecipeSYS_Result", I2S(i.result), GetStoredString(.gc, "RecipeSYS_Result", I2S(i.result)) + "|" + I2S(integer(i))) else call StoreString(.gc, "RecipeSYS_Result", I2S(i.result), I2S(integer(i))) endif set RECIPES[count] = i set count = count + 1 return i endmethod private method ClearRecipeFromItem takes integer it, boolean isResult returns nothing local integer re = integer(this) local integer i = 0 local integer j = 0 local string sg = GetStoredString(recipe.gc, "RecipeSYS", I2S(it)) local string sw local string mKey = "RecipeSYS" if isResult then set mKey = "RecipeSYS_Result" set sg = GetStoredString(recipe.gc, mKey, I2S(it)) endif if it == 0 then return endif loop loop set sw = SubString(sg, j, j + 1) exitwhen sw == "" or sw == "|" set j = j + 1 endloop if S2I(SubString(sg, i, j + 1)) == re then if i == 0 then if sw == "" then call FlushStoredString(recipe.gc, mKey, I2S(it)) else call StoreString(recipe.gc, mKey, I2S(it), SubString(sg, j + 1, StringLength(sg))) endif else if sw == "" then call StoreString(recipe.gc, mKey, I2S(it), SubString(sg, 0, i - 1)) else call StoreString(recipe.gc, mKey, I2S(it), SubString(sg, 0, i - 1) + SubString(sg, j + 1, StringLength(sg))) endif endif exitwhen true endif exitwhen sw == "" set i = j + 1 set j = i endloop endmethod method onDestroy takes nothing returns nothing local integer i = 0 loop call .ClearRecipeFromItem(.items[i], false) set i = i + 1 exitwhen i == 6 endloop call .ClearRecipeFromItem(.result, true) set .result = 0 endmethod endstruct private function GetItemTypeRecipes takes integer i, boolean isResult returns recipes local recipes r = recipes.create() local string s = GetStoredString(recipe.gc, "RecipeSYS", I2S(i)) local string work = "" local string worg local integer j = 0 local integer k = 0 if isResult then set s = GetStoredString(recipe.gc, "RecipeSYS_Result", I2S(i)) endif loop loop set worg = SubString(s, j, j + 1) exitwhen worg == "" or worg == "|" or worg == null set work = work + worg set j = j + 1 endloop set r[k] = recipe(S2I(work)) set k = k + 1 set work = "" exitwhen worg == "" or worg == null set j = j + 1 endloop return r endfunction private function RecipesRelease takes recipes r returns nothing local integer i = 0 loop exitwhen r[i] == 0 or i == recipes.size set r[i] = 0 set i = i + 1 endloop call r.destroy() endfunction //**************************************************** //** Recipes Without Charges ** //**************************************************** function AddRecipe takes integer item1, integer item2, integer item3, integer item4, integer item5, integer item6, integer result returns recipe return recipe.create(item1, item2, item3, item4, item5, item6, result, "", "", false, 0) endfunction function AddRecipeEx takes integer item1, integer item2, integer item3, integer item4, integer item5, integer item6, integer result, string sfx, string attachmentPoint returns recipe return recipe.create(item1, item2, item3, item4, item5, item6, result, sfx, attachmentPoint, false, 0) endfunction //**************************************************** //** Recipes With Charges ** //**************************************************** function AddRecipeWithCharges takes integer item1, integer item2, integer item3, integer item4, integer item5, integer item6, integer result, integer chargeType returns recipe return recipe.create(item1, item2, item3, item4, item5, item6, result, "", "", true, chargeType) endfunction function AddRecipeWithChargesEx takes integer item1, integer item2, integer item3, integer item4, integer item5, integer item6, integer result, integer chargeType, string sfx, string attachmentPoint returns recipe return recipe.create(item1, item2, item3, item4, item5, item6, result, sfx, attachmentPoint, true, chargeType) endfunction //**************************************************** //** Removing Recipes ** //**************************************************** function RemoveRecipeByResult takes integer result returns nothing local recipes r = GetItemTypeRecipes(result, true) local integer i = 0 loop exitwhen r[i] == 0 call recipe(r[i]).destroy() set i = i + 1 endloop call RecipesRelease(r) endfunction //**************************************************** //** Disabling and enabling recipes ** //**************************************************** function EnableRecipeByResult takes integer result, boolean enable returns nothing local recipes r = GetItemTypeRecipes(result, true) local integer i = 0 loop exitwhen r[i] == 0 set recipe(r[i]).enabled = enable set i = i + 1 endloop call RecipesRelease(r) endfunction //**************************************************** //** Disassembling Combined Items ** //**************************************************** function DisassembleItem takes item whichItem, unit whichUnit returns nothing local integer i = count - 1 local integer id = GetItemTypeId(whichItem) local recipes r = GetItemTypeRecipes(id, true) local real x = GetItemX(whichItem) local real y = GetItemY(whichItem) local recipe re = recipe(GetItemUserData(whichItem)) local boolean b = IsTriggerEnabled(GetTriggeringTrigger()) local boolean c = IsTriggerEnabled(TRIGGER) if b then call DisableTrigger(GetTriggeringTrigger()) //To avoid clashing with some events. endif if re == recipe(0) or USE_ITEM_DATA == false or re.result != id then //The last one just in case the recipe has been destroyed. if r[0] == 0 then if b then call EnableTrigger(GetTriggeringTrigger()) endif return endif set re = recipe(r[0]) call RecipesRelease(r) endif call RemoveItem(whichItem) set i = 0 //Should the items be created at a location or for a unit? if whichUnit == null then loop call CreateItem(re.items[i], x, y) set i = i + 1 exitwhen i == 6 endloop else if c then call DisableTrigger(TRIGGER) endif loop call UnitAddItemById(whichUnit, re.items[i]) set i = i + 1 exitwhen i == 6 endloop if c then call EnableTrigger(TRIGGER) endif endif if b then call EnableTrigger(GetTriggeringTrigger()) endif endfunction function DisassembleItemByRecipe takes item whichItem, unit whichUnit, recipe re returns nothing local integer i = 0 local integer itemID = GetItemTypeId(whichItem) local real x = GetItemX(whichItem) local real y = GetItemY(whichItem) local boolean b = IsTriggerEnabled(GetTriggeringTrigger()) local boolean c = IsTriggerEnabled(TRIGGER) if re.result == itemID then if b then call DisableTrigger(GetTriggeringTrigger()) endif call RemoveItem(whichItem) if whichUnit == null then loop call CreateItem(re.items[i], x, y) set i = i + 1 exitwhen i == 6 endloop else if c then call DisableTrigger(TRIGGER) endif loop call UnitAddItemById(whichUnit, re.items[i]) set i = i + 1 exitwhen i == 6 endloop if c then call EnableTrigger(TRIGGER) endif endif if b then call EnableTrigger(GetTriggeringTrigger()) endif endif endfunction //**************************************************** //** Combining ** //**************************************************** private function Combine takes recipe rec, unit u returns boolean local integer array itemsReq local integer itemInSlot local integer topCharges = 0 local integer sumCharges = 0 local integer i = 0 local integer j = 0 local item resu local item array itemsToCombine //Setting the items. loop set itemsReq[i] = rec.items[i] set i = i + 1 exitwhen i == 6 endloop set i = 0 //Finding the items. loop set itemInSlot = GetItemTypeId(UnitItemInSlot(u, i)) loop if itemsReq[j] == itemInSlot and itemInSlot != 0 then set itemsToCombine[j] = UnitItemInSlot(u, i) set itemsReq[j] = 0 exitwhen true endif set j = j + 1 exitwhen j == 6 endloop set j = 0 set i = i + 1 exitwhen i == 6 endloop set i = 0 set j = 0 //Checking if all items were found. loop if itemsReq[i] != 0 then loop set itemsToCombine[j] = null set j = j + 1 exitwhen j == 6 endloop return false endif set i = i + 1 exitwhen i == 6 endloop set i = 0 //Remove the old items. loop //Set the different charge amounts in case the result has charges. set j = GetItemCharges(itemsToCombine[i]) set sumCharges = sumCharges + j if j > topCharges then set topCharges = j endif call RemoveItem(itemsToCombine[i]) set itemsToCombine[i] = null set i = i + 1 exitwhen i == 6 endloop //Create the result. set resu = UnitAddItemById(u, rec.result) call DestroyEffect(AddSpecialEffectTarget(rec.sfx, u, rec.point)) //Set charges if it should have any. if rec.resultHasCharges then if rec.chargeType == 0 then call SetItemCharges(resu, sumCharges) elseif rec.chargeType == -1 then call SetItemCharges(resu, topCharges) else call SetItemCharges(resu, rec.chargeType) endif endif //Set the data if wanted. if USE_ITEM_DATA then call SetItemUserData(resu, integer(rec)) endif set bj_lastCreatedItem = resu set resu = null return true endfunction //**************************************************** //** Recipe Finding ** //**************************************************** function CheckForRecipes takes item check, unit u returns boolean local integer manip = GetItemTypeId(check) local recipes r = GetItemTypeRecipes(manip, false) local integer i = 0 local recipe re loop exitwhen r[i] == 0 set re = recipe(r[i]) if re.enabled then if Combine(re, u) then return true endif endif set i = i + 1 endloop call RecipesRelease(r) return false endfunction private function Check takes nothing returns boolean local unit u = GetTriggerUnit() local integer manip = GetItemTypeId(GetManipulatedItem()) local recipes r = GetItemTypeRecipes(manip, false) local integer i = 0 local recipe re loop exitwhen r[i] == 0 set re = recipe(r[i]) if re.enabled then if Combine(re, u) then return true endif endif set i = i + 1 endloop call RecipesRelease(r) set u = null return false endfunction //===================================================================== private function SafeFilt takes nothing returns boolean return true endfunction //===================================================================== private function Init takes nothing returns nothing local integer index = 0 if AUTO_COMBINE then loop call TriggerRegisterPlayerUnitEvent(TRIGGER, Player(index), EVENT_PLAYER_UNIT_PICKUP_ITEM, Filter(function SafeFilt)) set index = index + 1 exitwhen index == bj_MAX_PLAYER_SLOTS endloop call TriggerAddCondition(TRIGGER, Condition(function Check)) endif call FlushGameCache(InitGameCache(GC_PATH)) set recipe.gc = InitGameCache(GC_PATH) endfunction endlibrary Hash table:library RecipeSYS initializer Init uses Hash globals // ¤ ¤ // ( *'*-._.-*'*-._.-*'*-._.-*'* ) // ) RecipeSYS configuration ( // ( *'*-._.-*'*-._.-*'*-._.-*'* ) // ¤ ¤ private constant boolean AUTO_COMBINE = true //Whether you want the system to automatically combine //the ingredients of a recipe to the result when a unit //has all of them. private constant boolean USE_ITEM_DATA = true //Whether you allow the system to manipulate the //custom values of the items created by the system. private constant string SFX_PATH = "Abilities\\Spells\\Items\\TomeOfRetraining\\TomeOfRetrainingCaster.mdl" //The path of the default effect. private constant string SFX_POINT = "origin" //The default attachment point. // ¤ ¤ // ( *'*-._.-*'*-._.-*'*-._.-*'* ) // )DO NOT EDIT PAST THIS POINT( // ( *'*-._.-*'*-._.-*'*-._.-*'* ) // )Well, you can if you really( // ( want to, but only if you ) // )know what you're doing. And( // ( it's not needed, anyways. ) // )*'*-._.-*'*-._.-*'*-._.-*'*( // ¤ ¤ public constant trigger TRIGGER = CreateTrigger() private recipe array RECIPES private integer count = 0 private string array INGREDIENT_IN private string array RESULT_IN private hashtable ingTable private hashtable resTable endglobals type recipes extends integer array [50] struct recipe integer array items [6] integer result integer chargeType string sfx string point boolean resultHasCharges boolean enabled static method create takes integer i1, integer i2, integer i3, integer i4, integer i5, integer i6, integer result, string sfx, string attPoint, boolean charges, integer chargetype returns recipe local recipe i = recipe.allocate() local boolean array b local integer j = 0 local integer k set i.items[0] = i1 set i.items[1] = i2 set i.items[2] = i3 set i.items[3] = i4 set i.items[4] = i5 set i.items[5] = i6 set i.result = result set i.enabled = true set i.resultHasCharges = charges set i.chargeType = chargetype set b[0] = true set b[1] = i2 != i1 set b[2] = i3 != i2 and i3 != i1 set b[3] = i4 != i3 and i4 != i2 and i4 != i1 set b[4] = i5 != i4 and i5 != i3 and i5 != i2 and i5 != i1 set b[5] = i6 != i5 and i6 != i4 and i6 != i3 and i6 != i2 and i6 != i1 if sfx == "" then set i.sfx = SFX_PATH else set i.sfx = sfx endif if attPoint == "" then set i.point = SFX_POINT else set i.point = attPoint endif loop if i.items[j] != 0 and b[j] then set k = ingTable.Search(i.items[j]) if k != -1 then set INGREDIENT_IN[k] = INGREDIENT_IN[k] + "|" + I2S(integer(i)) else set k = ingTable.Hash(i.items[j]) set INGREDIENT_IN[k] = I2S(integer(i)) endif endif set j = j + 1 exitwhen j == 6 endloop set k = resTable.Search(i.result) if k != -1 then set RESULT_IN[k] = RESULT_IN[k] + "|" + I2S(integer(i)) else set k = resTable.Hash(i.result) set RESULT_IN[k] = I2S(integer(i)) endif set RECIPES[count] = i set count = count + 1 return i endmethod private method ClearRecipeFromItem takes integer it, boolean isResult returns nothing local integer re = integer(this) local integer i = 0 local integer j = 0 local string sg local string sw local integer key if it == 0 then return endif if isResult then set key = resTable.Search(it) set sg = RESULT_IN[key] else set key = ingTable.Search(it) set sg = INGREDIENT_IN[key] endif loop loop set sw = SubString(sg, j, j + 1) exitwhen sw == "" or sw == "|" set j = j + 1 endloop if S2I(SubString(sg, i, j + 1)) == re then if i == 0 then if sw == "" then if isResult then set resTable = resTable.Remove(it) else set ingTable = ingTable.Remove(it) endif else if isResult then set RESULT_IN[key] = SubString(sg, j + 1, StringLength(sg)) else set INGREDIENT_IN[key] = SubString(sg, j + 1, StringLength(sg)) endif endif else if sw == "" then if isResult then set RESULT_IN[key] = SubString(sg, 0, i - 1) else set INGREDIENT_IN[key] = SubString(sg, 0, i - 1) endif else if isResult then set RESULT_IN[key] = SubString(sg, 0, i - 1) + SubString(sg, j + 1, StringLength(sg)) else set INGREDIENT_IN[key] = SubString(sg, 0, i - 1) + SubString(sg, j + 1, StringLength(sg)) endif endif endif exitwhen true endif exitwhen sw == "" set i = j + 1 set j = i endloop endmethod method onDestroy takes nothing returns nothing local integer i = 0 loop call .ClearRecipeFromItem(.items[i], false) set i = i + 1 exitwhen i == 6 endloop call .ClearRecipeFromItem(.result, true) set .result = 0 endmethod endstruct private function GetItemTypeRecipes takes integer i, boolean isResult returns recipes local recipes r = recipes.create() local string s local string work = "" local string worg local integer j = 0 local integer k = 0 if isResult then set s = RESULT_IN[resTable.Search(i)] else set s = INGREDIENT_IN[ingTable.Search(i)] endif loop loop set worg = SubString(s, j, j + 1) exitwhen worg == "" or worg == "|" or worg == null set work = work + worg set j = j + 1 endloop set r[k] = recipe(S2I(work)) set k = k + 1 set work = "" exitwhen worg == "" or worg == null set j = j + 1 endloop return r endfunction private function RecipesRelease takes recipes r returns nothing local integer i = 0 loop exitwhen r[i] == 0 or i == recipes.size set r[i] = 0 set i = i + 1 endloop call r.destroy() endfunction //**************************************************** //** Recipes Without Charges ** //**************************************************** function AddRecipe takes integer item1, integer item2, integer item3, integer item4, integer item5, integer item6, integer result returns recipe return recipe.create(item1, item2, item3, item4, item5, item6, result, "", "", false, 0) endfunction function AddRecipeEx takes integer item1, integer item2, integer item3, integer item4, integer item5, integer item6, integer result, string sfx, string attachmentPoint returns recipe return recipe.create(item1, item2, item3, item4, item5, item6, result, sfx, attachmentPoint, false, 0) endfunction //**************************************************** //** Recipes With Charges ** //**************************************************** function AddRecipeWithCharges takes integer item1, integer item2, integer item3, integer item4, integer item5, integer item6, integer result, integer chargeType returns recipe return recipe.create(item1, item2, item3, item4, item5, item6, result, "", "", true, chargeType) endfunction function AddRecipeWithChargesEx takes integer item1, integer item2, integer item3, integer item4, integer item5, integer item6, integer result, integer chargeType, string sfx, string attachmentPoint returns recipe return recipe.create(item1, item2, item3, item4, item5, item6, result, sfx, attachmentPoint, true, chargeType) endfunction //**************************************************** //** Removing Recipes ** //**************************************************** function RemoveRecipeByResult takes integer result returns nothing local recipes r = GetItemTypeRecipes(result, true) local integer i = 0 loop exitwhen r[i] == 0 call recipe(r[i]).destroy() set i = i + 1 endloop call RecipesRelease(r) endfunction //**************************************************** //** Disabling and enabling recipes ** //**************************************************** function EnableRecipeByResult takes integer result, boolean enable returns nothing local recipes r = GetItemTypeRecipes(result, true) local integer i = 0 loop exitwhen r[i] == 0 set recipe(r[i]).enabled = enable set i = i + 1 endloop call RecipesRelease(r) endfunction //**************************************************** //** Disassembling Combined Items ** //**************************************************** function DisassembleItem takes item whichItem, unit whichUnit returns nothing local integer i = count - 1 local integer id = GetItemTypeId(whichItem) local recipes r = GetItemTypeRecipes(id, true) local real x = GetItemX(whichItem) local real y = GetItemY(whichItem) local recipe re = recipe(GetItemUserData(whichItem)) local boolean b = IsTriggerEnabled(GetTriggeringTrigger()) local boolean c = IsTriggerEnabled(TRIGGER) if b then call DisableTrigger(GetTriggeringTrigger()) //To avoid clashing with some events. endif if re == recipe(0) or USE_ITEM_DATA == false or re.result != id then //The last one just in case the recipe has been destroyed. if r[0] == 0 then if b then call EnableTrigger(GetTriggeringTrigger()) endif return endif set re = recipe(r[0]) call RecipesRelease(r) endif call RemoveItem(whichItem) set i = 0 //Should the items be created at a location or for a unit? if whichUnit == null then loop call CreateItem(re.items[i], x, y) set i = i + 1 exitwhen i == 6 endloop else if c then call DisableTrigger(TRIGGER) endif loop call UnitAddItemById(whichUnit, re.items[i]) set i = i + 1 exitwhen i == 6 endloop if c then call EnableTrigger(TRIGGER) endif endif if b then call EnableTrigger(GetTriggeringTrigger()) endif endfunction function DisassembleItemByRecipe takes item whichItem, unit whichUnit, recipe re returns nothing local integer i = 0 local integer itemID = GetItemTypeId(whichItem) local real x = GetItemX(whichItem) local real y = GetItemY(whichItem) local boolean b = IsTriggerEnabled(GetTriggeringTrigger()) local boolean c = IsTriggerEnabled(TRIGGER) if re.result == itemID then if b then call DisableTrigger(GetTriggeringTrigger()) endif call RemoveItem(whichItem) if whichUnit == null then loop call CreateItem(re.items[i], x, y) set i = i + 1 exitwhen i == 6 endloop else if c then call DisableTrigger(TRIGGER) endif loop call UnitAddItemById(whichUnit, re.items[i]) set i = i + 1 exitwhen i == 6 endloop if c then call EnableTrigger(TRIGGER) endif endif if b then call EnableTrigger(GetTriggeringTrigger()) endif endif endfunction //**************************************************** //** Combining ** //**************************************************** private function Combine takes recipe rec, unit u returns boolean local integer array itemsReq local integer itemInSlot local integer topCharges = 0 local integer sumCharges = 0 local integer i = 0 local integer j = 0 local item resu local item array itemsToCombine //Setting the items. loop set itemsReq[i] = rec.items[i] set i = i + 1 exitwhen i == 6 endloop set i = 0 //Finding the items. loop set itemInSlot = GetItemTypeId(UnitItemInSlot(u, i)) loop if itemsReq[j] == itemInSlot and itemInSlot != 0 then set itemsToCombine[j] = UnitItemInSlot(u, i) set itemsReq[j] = 0 exitwhen true endif set j = j + 1 exitwhen j == 6 endloop set j = 0 set i = i + 1 exitwhen i == 6 endloop set i = 0 set j = 0 //Checking if all items were found. loop if itemsReq[i] != 0 then loop set itemsToCombine[j] = null set j = j + 1 exitwhen j == 6 endloop return false endif set i = i + 1 exitwhen i == 6 endloop set i = 0 //Remove the old items. loop //Set the different charge amounts in case the result has charges. set j = GetItemCharges(itemsToCombine[i]) set sumCharges = sumCharges + j if j > topCharges then set topCharges = j endif call RemoveItem(itemsToCombine[i]) set itemsToCombine[i] = null set i = i + 1 exitwhen i == 6 endloop //Create the result. set resu = UnitAddItemById(u, rec.result) call DestroyEffect(AddSpecialEffectTarget(rec.sfx, u, rec.point)) //Set charges if it should have any. if rec.resultHasCharges then if rec.chargeType == 0 then call SetItemCharges(resu, sumCharges) elseif rec.chargeType == -1 then call SetItemCharges(resu, topCharges) else call SetItemCharges(resu, rec.chargeType) endif endif //Set the data if wanted. if USE_ITEM_DATA then call SetItemUserData(resu, integer(rec)) endif set bj_lastCreatedItem = resu set resu = null return true endfunction //**************************************************** //** Recipe Finding ** //**************************************************** function CheckForRecipes takes item check, unit u returns boolean local integer manip = GetItemTypeId(check) local recipes r = GetItemTypeRecipes(manip, false) local integer i = 0 local recipe re loop exitwhen r[i] == 0 set re = recipe(r[i]) if re.enabled then if Combine(re, u) then return true endif endif set i = i + 1 endloop call RecipesRelease(r) return false endfunction private function Check takes nothing returns boolean local unit u = GetTriggerUnit() local integer manip = GetItemTypeId(GetManipulatedItem()) local recipes r = GetItemTypeRecipes(manip, false) local integer i = 0 local recipe re loop exitwhen r[i] == 0 set re = recipe(r[i]) if re.enabled then if Combine(re, u) then return true endif endif set i = i + 1 endloop call RecipesRelease(r) set u = null return false endfunction //===================================================================== private function SafeFilt takes nothing returns boolean return true endfunction //===================================================================== private function Init takes nothing returns nothing local integer index = 0 if AUTO_COMBINE then loop call TriggerRegisterPlayerUnitEvent(TRIGGER, Player(index), EVENT_PLAYER_UNIT_PICKUP_ITEM, Filter(function SafeFilt)) set index = index + 1 exitwhen index == bj_MAX_PLAYER_SLOTS endloop call TriggerAddCondition(TRIGGER, Condition(function Check)) endif set ingTable = hashtable.create() set resTable = hashtable.create() endfunction endlibrary ![]() |
| 08-26-2008, 10:01 PM | #12 |
I really don't know what you're doing in the GetItemTypeRecipes function. Why work with strings when you could easily have stored integers to GC? Speaking of GC, you shouldn't be creating your own cache for this, you should use an external gamecache library like Table. |
| 08-27-2008, 04:40 AM | #13 |
Why I'm working with strings is that I couldn't figure out a way to use integers without limiting an item-type to only be cabable of being used in one recipe. GetItemTypeRecipes just separates the integers (=recipes) stored to the string, sets them to the array and returns the array. And I'll look to that Table. :) |
| 08-27-2008, 01:53 PM | #14 |
Couldn't you just create a dynamic array for each item that stores all the recipies that item is involved in, and then link that array (which is just an integer when vJass compiles to Jass) to the item type via GC? Seems like the only sane way to do this. |
| 08-27-2008, 07:41 PM | #15 | ||
At some point I came up with an idea of using dynamic arrays, but I abandoned that idea as I thought it'd restrict the system too much (if you increase the amount of recipes an item can be in, the amount of different item-types that can be used goes down), and I didn't know a way to store them well when in dynamic arrays. Didn't know they are that much like structs. So thanks for Anitarf, Vexorian, and everyone else who has left suggestions/comments. So I think it's about the time to release the version 0.6 after tweaking the code kinda much, now using Table and dynamic arrays and stuff. And it even worked in my tests.
Quote:
![]() Edit: Heh, maybe I shouldn't do this just before getting to bed. I noted I've been using strings to store the data, even though I could've just used integers. Will be fixed for the next version, don't worry. |
