Skip to content

Posts from Scripts

4.8 (8 ratings)
3 years ago
Auto-translated

Thank you very much for the detailed comments from esteemed Dolgiy and esteemed Jack of Shadows.

The problem is that, as I understand it, if I return not nil in the UnitMove hook, the unit should not move further. However, for some reason, the unit casts a spell and makes its move, and it makes the move first. I rechecked Novik's documentation, and it also states that UnitMove should be called before each turn of the creature stack.

That is, the expected sequence of actions is:

1. The creature receives its turn.

2. The UnitMove hook is triggered.

3. In the hook, I apply blindness and return not nil.

4. The creature remains in its place, playing the spell animation.

The actual sequence of actions is:

1. The creature receives its turn.

2. The UnitMove hook is triggered.

3. The creature performs an action (moves forward or attacks if it can reach).

4. The action is passed to my handler, and the creature casts a spell.

5. not nil is returned.

Could you please advise me on where I might have made a mistake? I understand that the body of the hook should be executed first, and then the creature's action, and not the other way around.

User Avatar
3 years ago
Auto-translated
What does your script look like?
User Avatar
3 years ago
Auto-translated
Everything should work as expected; there aren't any hidden tricks. You need to surround the code with print statements and see if it crashes somewhere before exiting UnitMove().
In reply to Jack_of_shadows
User Avatar
3 years ago
Auto-translated
Hi everyone! I have a question.
I wrote a script that works like the transformation mechanic in the Redhaven Campaign, but it's very simple. So, when I put, for example, 20 skeleton archers into the transformation mechanic, I get 20 of my custom skeleton units. BUT, if I put in two stacks of 10 (which is a total of 20), the result is 40 (!)
----Transformation Mechanic: Hafad can transform ordinary undead into new necromantic units----
function CustomAbility(hero, id)
if (id == CUSTOM_ABILITY_3) then
Hero = hero
MakeHeroInteractWithObject(hero, "ritual")
sleep(10)
for i=0,6 do
local type, num = GetObjectArmySlotCreature("ritual", i)
if (type >= 30 and type <= 42 and mod(type, 2) == 0) or (type >= 152 and type <= 158) then
startThread(NecroRitual)
SetObjectOwner("ritual", PLAYER_2)
end
end
local x,y = GetObjectPosition("Hafad")
PlayVisualEffect("/Effects/_(Effect)/Spells/Curse.xdb#xpointer(/Effect)","","tag1", x+0.5,y+0.5,0,GROUND);
PlayVisualEffect("/Effects/_(Effect)/Spells/DisruptingRay.xdb#xpointer(/Effect)","","tag1", x+0.5,y+0.5,0,GROUND);
sleep(2)
PlayVisualEffect("/Effects/_(Effect)/Spells/AnimateDead.xdb#xpointer(/Effect)","","tag1", x+0.5,y+0.5,0,GROUND);
local Level = GetHeroLevel("Hafad")
local Spell = GetHeroStat("Hafad", STAT_SPELL_POWER)
local quantity = 0.35 * Level + Spell
AddHeroCreatures("Hafad", 40, quantity)
ShowFlyingSign("/Text/MasterOfDeath.txt", "Hafad", 1, 5.0)
sleep(1)
ControlHeroCustomAbility(hero, CUSTOM_ABILITY_3, CUSTOM_ABILITY_DISABLED)
end
end

function NecroRitual()
for i=0,6 do
local type, num = GetObjectArmySlotCreature("ritual", i)
if GetObjectArmySlotCreature("ritual", i) == 30 then
RemoveObjectCreatures('ritual', type, num, i)
AddHeroCreatures(Hero, 896, num)
elseif type == 32 then
RemoveObjectCreatures('ritual', type, num, i)
AddHeroCreatures(Hero, 897, num)
elseif type == 34 then
RemoveObjectCreatures('ritual', type, num, i)
AddHeroCreatures(Hero, 898, num)
elseif type == 36 then
RemoveObjectCreatures('ritual', type, num, i)
AddHeroCreatures(Hero, 899, num)
elseif type == 38 then
RemoveObjectCreatures('ritual', type, num, i)
AddHeroCreatures(Hero, 900, num)
elseif type == 90 then
RemoveObjectCreatures('ritual', type, num, i)
AddHeroCreatures(Hero, 901, num)
elseif type == 42 then
RemoveObjectCreatures('ritual', type, num, i)
AddHeroCreatures(Hero, 902, num)
end;
end;
end;
In reply to BlueHeavenHero
User Avatar
3 years ago
Auto-translated
I have a hunch that the GetObjectArmySlotCreature() function was primarily created to retrieve the ID from a slot, rather than the number of units, and it returns the total number of creature data.

Added 19 minutes later
Or maybe sleep() isn't sufficient, which is why the number of creatures gets counted twice.
In reply to Долгий
User Avatar
3 years ago
Auto-translated
Long
I have a hunch that the GetObjectArmySlotCreature() function was mainly created to get the ID from a slot, rather than the number of units, and returns the total number of creature data.

Added 19 minutes later
Or maybe sleep() is not enough, which is why the number of creatures manages to be counted twice.
And where would you advise me to put sleep()? I want to test the second option first.
In reply to BlueHeavenHero
User Avatar
3 years ago
Auto-translated
BlueHeavenHero
Where would you recommend placing the sleep() function? I want to test the second option first.
Inside the for loop, in the NecroRitual() function.
In reply to Долгий
User Avatar
3 years ago
Auto-translated
Long
Inside the for loop, the NecroRitual() function.
So, nothing has changed for me. It seems I need to rewrite the entire ritual script.
In reply to BlueHeavenHero
User Avatar
3 years ago
Auto-translated
I don't quite understand this part: ``` for i=0,6 do local type, num = GetObjectArmySlotCreature("ritual", i) if (type >= 30 and type <= 42 and mod(type, 2) == 0) or (type >= 152 and type <= 158) then startThread(NecroRitual) SetObjectOwner("ritual", PLAYER_2) end end. ``` And then in the ritual function: ``` for i=0,6 do local type, num = GetObjectArmySlotCreature("ritual", i) if GetObjectArmySlotCreature("ritual", i) == 30 then RemoveObjectCreatures('ritual', type, num, i) ... ``` Why are you setting the hero as the owner for each slot? It seems like this could be done outside the loop. And why are you starting a new thread for each slot? I haven't run the script, but it looks like you're starting 2 threads for two slots that run in parallel, and when the processing of the second cycle in the ritual function goes through all the slots again, the first slot hasn't been cleared yet (by the first thread). It seems that if you remove the loop in the function or remove the duplicate threads, everything should work. Like this: ``` MakeHeroInteractWithObject(hero, "ritual") sleep(10) startThread(NecroRitual) SetObjectOwner("ritual", PLAYER_2) local x,y = GetObjectPosition(Hero) ... ``` Also, this is purely aesthetic, but since you're getting the hero's name from the function, why are you writing "Hafad" in other places?
In reply to LetoX
User Avatar
3 years ago
Auto-translated
LetoX
I don't quite understand this part -

for i=0,6 do
local type, num = GetObjectArmySlotCreature("ritual", i)
if (type >= 30 and type <= 42 and mod(type, 2) == 0) or (type >= 152 and type <= 158) then
startThread(NecroRitual)
SetObjectOwner("ritual", PLAYER_2)
end
end.

and then in the ritual function -

for i=0,6 do
local type, num = GetObjectArmySlotCreature("ritual", i)
if GetObjectArmySlotCreature("ritual", i) == 30 then
RemoveObjectCreatures('ritual', type, num, i) ...

Why are you setting the hero as the owner for each slot? Ideally, this could be done outside the loop. And why are you starting a new thread for each slot? I haven't run the script, but it looks like you're starting 2 threads for two slots that run in parallel (sort of), and when the processing of the second cycle in the ritual function goes through all the slots again, the first slot hasn't been cleared yet (by the first thread). It seems that if you remove the loop in the function or remove the duplicated threads, everything should work.
I don't understand these scripts very well myself, so I probably did it twice.
LetoX

Like this:

MakeHeroInteractWithObject(hero, "ritual")
sleep(10)
startThread(NecroRitual)
SetObjectOwner("ritual", PLAYER_2)
local x,y = GetObjectPosition(Hero) ...
Also, this is purely aesthetic, but since you're taking the hero's name from the function, why are you writing "Hafad" in other places?
Well, it's just that Hafad is the one who should perform the ritual and receive the troops; no one else has this ability, and I left the hero's name from the function in other places.


Added 44 seconds ago
Right now, I'm tinkering with the Redhaven script for turning ordinary people into green ones. This is quite a challenge...
User Avatar
2 years ago
Auto-translated
Is it possible to create such scripts in Heroes of Might and Magic:

1) A neutral city that cannot be captured. The city would essentially function like a Shrine of the Prophet (preferably reusable) – a hero could approach and take on a quest. Then, they could complete it and receive a reward (e.g., an army). However, they wouldn't be able to enter the city to build structures or purchase creatures.

2) Can any building be made to function like a Shrine of the Prophet? You approach an Archer's Tower, and it asks you to bring, say, 100 wood, and then it will make arrows and join you in battle... Or you swim up to a Mermaid object, and it asks you to find a certain artifact... Does this require setting up a script zone in front of the object, or can it be changed in the object's settings?

3) Is it possible to make it so that when a hero dies/loses, they don't die but are teleported to a random location underground? (Let's say with a specific group of units – of course, they lose their current army and have to find a way out – as if from another world).

4) Can teleportation be a reward? For example, you complete a Griffin quest, and the hero ends up on the other side of the mountains (as if the birds carried them).

5) Can objects appear on the map? Not monsters that appear on a certain week, but, say, mines/enhancement sites/or cacti. For example, to show that a drought has arrived, and suddenly a group of dry trees appears on the map. And the hero can complete a quest/battle to remove these dry trees and restore the beautiful view.

P.S.: I might have more ideas later, but that's it for now.
In reply to Simsa
User Avatar
2 years ago
Auto-translated

Simsa,
1 and 2: Use SetObjectEnabled("object", true (it works as intended) or false (it becomes like static scenery that can be interacted with)), after which you can place a touch trigger (OBJECT_TOUCH_TRIGGER) on the object that will call a function, which will handle quests and dialogues.

3.
1) If there is a quest to save a hero, it needs to be reworked into a "dummy" quest (switch to OBJECTIVE_KIND_MANUAL if it was switched), i.e., make the quest fail only through a script based on some condition, and not technically, otherwise the scenario will always play out. Also, to make quests fail without ending the map, you must always set Ignore = true in the quest skeletons.
2) Regarding teleporting the hero in case of a loss: Put the main hero into the player's reserve, remove him from the map because the reserve hero should not be on it initially. At the beginning of the plot, place him on the map using a script (DeployReserveHero("scripted hero name", x, y, z where to place)) + you can also rotate him using the function SetObjectRotation("scripted hero name", degrees (counterclockwise)). Before that, write a trigger for the player losing heroes and a function that will be launched, in which we will track that if the player lost the specific hero, we will put him back on the map in another location (also through DeployReserveHero), give him the necessary army, and then do whatever you want. I recommend giving the reserve hero at least some army by editing his parameters; otherwise, when he spawns, a random army will be generated based on his specialization.

4. Yes, you can use a trigger to track changes in the status of quests to see which quest has its status changed to "completed," and upon fulfilling the condition, use the function to make the desired object SetObjectPosition().

5. You can spawn dwellings for units, static objects, resources, artifacts, creatures, caravans, and heroes (from the reserve). You cannot manipulate mines except to change their owners and turn their standard visits on/off using SetObjectEnabled. Only turning on/off works for objects that give bonuses. Regarding deleting created static objects, I don't know because I haven't worked with this functionality.

In reply to Азгалор
User Avatar
2 years ago
Auto-translated
Azgalor

Simsa,
Before that, we'll set up a trigger for the player losing heroes and a function that will be executed, which will track whether the lost hero was the one we need, and if so, it will place him back on the map in a different location (also using DeployReserveHero), give him the necessary army, and then you can decide what to do next. I recommend assigning at least some army to the reserve hero by editing his parameters; otherwise, when he spawns, a random army will be generated based on his specialization.

5. You can spawn dwellings, static objects, resources, artifacts, creatures, caravans, and heroes (from the reserve).

Thank you. I'd like to clarify further. Regarding teleporting the hero – ideally, I want a single, immortal hero who can travel the map without a town (I know that a hero can live without a town) and gather troops through quests. If I want the hero to teleport to different locations in the Dungeon, do I need to write a separate script for each location, or can I write a single script with a list of coordinates, and the script will randomly select coordinates? And if it's different scripts (one for each location), do I need to assign an army to the hero each time? For example, I want the hero to have air elementals as his troops after "death."

What exactly are "static objects"? Environmental objects (bushes, rocks, etc.)? As far as I understand, you can't recolor tiles, right? Like, can you replace grass with lava ground or snow with grass?

I think I read somewhere that you can work with light... for example, can you assign a certain glow to an object (I think this goes back to point 1 (false) – for example, a bush glows red – the hero encounters a script where a battle is triggered (like with a chest), and after winning, the bush loses its red glow and becomes normal. Or not a bush, but, say, a fountain. So, the script should have a condition that after completing the script's task (defeating enemies), the object should become true again?

Also:

6) Can you create rumors without a tavern? For example, I want the player to not be able to hire other heroes, but they can still learn some rumors. For this, you just need to add the necessary rumors to the units/objects on the map (for example, a warrior tells a story, but it's not a quest. Like in a tavern – somewhere in the desert, an artifact is buried – they say). Or you can place taverns, but without the ability to hire heroes there. But you can read rumors and see the enemy's army. In general, can this function of viewing the enemy's army (in the tavern and thief's den) be created with other objects? For example, a certain unit acts as a spy – for a certain amount or item (money/gems/artifact), it provides information – about the enemy's army or some secret.

7) Can you re-enable the fog of war? For example, I want the hero to be in the dark again in the Dungeon after another "death," even if he has already been there and explored everything.

8) To prevent random monsters from spawning in the Dungeon, should I disable the spawn weeks or specify that the spawn should only be on the surface? I wouldn't want to completely disable the spawn weeks, but I also don't want to end up with a bunch of elementals after the spawn week for dragons/archers/ent and just get stuck there without being able to get out.
User Avatar
2 years ago
Auto-translated
Read the Ogo-i guide for beginners and the Jack of Shadows FAQ. You'll find answers to many of your questions there!

6) Only through scripts. You can link interactions to units/objects that display random messages, and create a pool of these messages. If you need the messages to depend on events on the map, you need to create events for these events (for example, in a loop, check if the hero's set of artifacts has changed and add a corresponding rumor). Let me tell you, this is not a trivial task, not for a beginner. I recommend limiting yourself to simple, fixed rumors that you will have in a table:
custom_rumours={
"../Rumour1.txt",
"../ElseMoreRumours.txt",
"../ARumourToo.txt",
}

function NpcRumoursTalk(hero, obj)
if hero=="главный герой" then
local index = random(length(custom_rumours))
ShowFlyingSign(custom_rumours[index], obj, GetObjectOwner(hero), 10);
end
end

SetObjectEnabled("имя объекта", nil)
Trigger(OBJECT_TOUCH_TRIGGER, "имя объекта", "NpcRumoursTalk")

The simple script provided will display a pop-up message with a random rumor from the list from the specified object.

7) Not feasible.

8) Disabling the spawn week applies to all levels.

In reply to Simsa
User Avatar
2 years ago
Auto-translated

Simsa

Thank you. I'd like to clarify something. Regarding the hero's teleportation, ideally, I want a single, immortal hero who can travel the map without a town (I know that a hero can survive without a town) and gather troops by completing quests. If I want the hero to teleport to different locations in the underworld, do I need to write a separate script for each location, or can I write a single script that includes a list of coordinates, and then randomly select coordinates from that list? And if it's different scripts (one for each location), do I need to specify the hero's army each time? For example, I want the hero to have air elementals as fighters after "death."

What exactly is "static"? Is it environmental objects (bushes, rocks, etc.)? As far as I understand, can't tiles be recolored? For example, can grass be replaced with lava ground, or snow with grass?

I think I read somewhere that you can work with light... can you, for example, assign a glow to an object (I think this brings us back to point 1 (false) - for example, a bush glows red - the hero encounters a script where a battle is defined (like with a chest), and after winning, the bush loses its red glow and becomes normal. Or not a bush, but, say, a fountain. That is, the script should have a condition that after solving the script's task (defeating enemies), the object should become true again?

For such teleportations, it will be enough to have one table of coordinates and choose from them. You will have to specify the army for the hero anyway, because he appears from the reserve either with a standard army or with one that is pre-defined in the editor. Naturally, you will also have to transfer the progression, spells, and artifacts from the deceased hero to the hero from the reserve (of course, if this is necessary according to the logic).
Statics are basically any object that has the type AdvMapStatic. They can be created/deleted on the map at any time. Buildings, such as mines, have the type AdvMapBuilding, and they cannot be created.
You can configure the glow on objects in advance in the editor, and also using the SetObjectFlashlight/ResetObjectFlashlight functions. At the same time, the light source that you want to add to the object must be pre-entered into the map's resources, in the point lights section (maybe a slightly different name, I don't remember exactly).

Also, as Khottabych wrote, the standard scripting guide in the game files, or time-tested guides from Novik or Jack of Shadows, will answer most of your questions. They won't give you a complete understanding, but at least they will give you an idea of what you can do with scripts. I also recommend joining the VK group in Khottabych's signature; there is a lot of useful information there, including very specific scripting tricks. You can write to me on Telegram/Discord (in my profile); I can help you with any specific questions, not only about scripts but also about the editor in general.

Statistics

Welcome our newest member: recijeb

Users Online 3 users 1582 guests