Linked heroes

Maps and the art of mapmaking.
GohozoqPohobo
Leprechaun
Leprechaun
Posts: 26
Joined: 30 Sep 2007

Linked heroes

Unread postby GohozoqPohobo » 09 Nov 2007, 04:38

I'm trying to make a map where everyone has a 'special hero.'
The hero can die, but it will always be in the tavern and, further, nobody else can recruit him while that player lives.

Can I do that?

User avatar
Grumpy Old Wizard
Round Table Knight
Round Table Knight
Posts: 2205
Joined: 06 Jan 2006
Location: Tower Grump

Unread postby Grumpy Old Wizard » 09 Nov 2007, 07:03

It should be possible with TOTE. Have a look at the new script commands in the TOTE map editor manual. Here are a few commands you'll probably use.

AllowPlayerTavernHero
AllowPlayerTavernHero – allows to prohibit the appearance of the specified heroes in the
taverns that belong to a certain player.
Syntax
{{{
AllowPlayerTavernHero( playerID, heroName, allow )
}}}
Description
For the player with identifier "playerID", the hero with scripting name "heroName" will
now be generated/not generated in the tavern, depending on the "allow" parameter ("true"
to generate them, or "false" to not generate).


AllowHiringOfHeroInTown
AllowHiringOfHeroInTown – manages the possibility of hiring the specified heroes in the
specified town.
Syntax
{{{
AllowHiringOfHeroInTown( townName, heroName, allow )
}}}
Description
In the town "townName", the hero "heroName" is allowed or prohibited to hire.
The function works for all players, both AI and human.
"allow" has one of the following values :
* "0" – prohibit hiring the hero even if the heroes of his race can be hired ( see
[:../AllowHeroHiringByRaceInTown:] )
* "1" – allow hiring the hero even if the heroes of his race can not be hired
* "-1" – apply the hero’s race general rule to the hero

MakeHeroReturnToTavernAfterDeath
MakeHeroReturnToTavernAfterDeath – makes it so that after his defeat, the hero will always
return to his player’s tavern and wait for being hired.
Syntax
{{{
MakeHeroReturnToTavernAfterDeath( heroName, enable,
heroShouldStayAtTavernUntilHired = 0 )
}}}
Description
When "enable" equals to "true", it sets the hero "heroName" in the mode when in case of
any defeat, he immediately returns to his player’s tavern.
If a nonzero value is set for "heroShouldStayAtTavernUntilHired", the hero will be
staying in the tavern for an unlimited period of time, waiting for the player to hire him.

GOW
Frodo: "I wish the ring had never come to me. I wish none of this had happened."
Gandalf: "So do all who live to see such times but that is not for them to decide. All we have to decide is what to do with the time that is given to us."

GohozoqPohobo
Leprechaun
Leprechaun
Posts: 26
Joined: 30 Sep 2007

Unread postby GohozoqPohobo » 11 Nov 2007, 23:58

I'm certain I'm doing something wrong.
It says the function "MakeHeroReturnToTavernAfterDeath not defined." Please enlighten me.

In the same vein, I want the player's 2nd hero (i.e., the first one they hire from the tavern, or perhaps the first one that leaves the town, not including the starting hero) to be given artifacts they cannot lose.

I think I've got most of it, but I can't seem to figure how to make certain the script occurs for each player exactly once.

I've got this so far...

Trigger (PLAYER_ADD_HERO_TRIGGER, heroIsBorn(i));

function heroIsBorn (playerNum)

GiveArtefact(GetPlayerHeroes(playerNum)[1], 34, 1);
GiveArtefact(GetPlayerHeroes(playerNum)[1], 35, 1);

end;

But I can't see how I'm supposed to feed it the playerNum, or ensure it occurs exactly once.

User avatar
Grumpy Old Wizard
Round Table Knight
Round Table Knight
Posts: 2205
Joined: 06 Jan 2006
Location: Tower Grump

Unread postby Grumpy Old Wizard » 12 Nov 2007, 04:57

GohozoqPohobo wrote:I'm certain I'm doing something wrong.
It says the function "MakeHeroReturnToTavernAfterDeath not defined." Please enlighten me.
It would help if you posted exactly what you did. Here is how it should appear.

MakeHeroReturnToTavernAfterDeath(heroName, true, 1 );

Replace heroName with the internal scripting name of the heroe, which is not necessarily the same name that the player sees.

In order to determine what the internal scripting name is for the heroe, place the hero on the map, make sure he is highlighted, ant then click on the object properties tree button. Click over to the right of where you see "shared." Now click on the "...." button. On the right hand panel that comes up go down to where it says "Internal Name" and across from that you will see the name to use when scripting.

For example, if you placed Galib on the map you will see that his internal name is "Tan."
GohozoqPohobo wrote: In the same vein, I want the player's 2nd hero (i.e., the first one they hire from the tavern, or perhaps the first one that leaves the town, not including the starting hero) to be given artifacts they cannot lose.

I think I've got most of it, but I can't seem to figure how to make certain the script occurs for each player exactly once.

I've got this so far...

Trigger (PLAYER_ADD_HERO_TRIGGER, heroIsBorn(i));

function heroIsBorn (playerNum)

GiveArtefact(GetPlayerHeroes(playerNum)[1], 34, 1);
GiveArtefact(GetPlayerHeroes(playerNum)[1], 35, 1);

end;

But I can't see how I'm supposed to feed it the playerNum, or ensure it occurs exactly once.
You are going to need a conditional statement and a variable for each player. For example,
-------------------------------
--declare global variables--
-------------------------------
secondaryone =0;
secondarytwo =0;
You will need a vairable for each player. These variables are flags that will be set when the statements are executed once.

Now that you declared these variables near the top of your script, you will need conditionals to check these flags.

For example:

function heroIsBorn (playerNum)
if GetCurrentPlayer () == PLAYER_1 AND secondaryone == 0 then
secondaryone = 1; --set this flag so the instructions execute only once
GiveArtefact(GetPlayerHeroes(playerNum)[1], 34, 1);
GiveArtefact(GetPlayerHeroes(playerNum)[1], 35, 1);
end;
end;
Do a conditional for each of the players.

GOW
Frodo: "I wish the ring had never come to me. I wish none of this had happened."
Gandalf: "So do all who live to see such times but that is not for them to decide. All we have to decide is what to do with the time that is given to us."

GohozoqPohobo
Leprechaun
Leprechaun
Posts: 26
Joined: 30 Sep 2007

Unread postby GohozoqPohobo » 12 Nov 2007, 16:11

Something went wrong. Now the free levels don't even work.
Here's what I've got.
I tried declaring the globals before and after the first loop, to no avail.

for i = 1, 8, 1 do --do for player (this assumes eight players)
ChangeHeroStat (GetPlayerHeroes(i)[0], STAT_EXPERIENCE, 200000);
MakeHeroReturnToTavernAfterDeath(GetPlayerHeroes(i)[0], true, 1 )
end;

newHeroOne = 0;
newHeroTwo = 0;
newHeroThree = 0;
newHeroFour = 0;
newHeroFive = 0;
newHeroSix = 0;
newHeroSeven = 0;
newHeroEight = 0;

function heroIsBorn (playerNum)
if GetCurrentPlayer () == PLAYER_1 AND newHeroOne == 0 then
newHeroOne = 1;
GiveArtefact(GetPlayerHeroes(playerNum)[1], 34, 1);
GiveArtefact(GetPlayerHeroes(playerNum)[1], 35, 1);
end;

if GetCurrentPlayer () == PLAYER_2 AND newHeroTwo == 0 then
newHeroTwo = 1;
GiveArtefact(GetPlayerHeroes(playerNum)[1], 34, 1);
GiveArtefact(GetPlayerHeroes(playerNum)[1], 35, 1);
end;



.
.
.

if GetCurrentPlayer () == PLAYER_8 AND newHeroEight == 0 then
newHeroEight = 1;
GiveArtefact(GetPlayerHeroes(playerNum)[1], 34, 1);
GiveArtefact(GetPlayerHeroes(playerNum)[1], 35, 1);
end;
end;

GohozoqPohobo
Leprechaun
Leprechaun
Posts: 26
Joined: 30 Sep 2007

Unread postby GohozoqPohobo » 13 Nov 2007, 02:19

I just tried taking it apart and getting the free-level parts to work, and now I can't even get the globals to initialize.

They call them functions that aren't defined.

User avatar
Grumpy Old Wizard
Round Table Knight
Round Table Knight
Posts: 2205
Joined: 06 Jan 2006
Location: Tower Grump

Unread postby Grumpy Old Wizard » 13 Nov 2007, 02:20

The syntax error that caused nothing to work was AND being capitolized in the conditionals. AND should just be and.

Also, your statements for giveing arttifacts had to be broken up into a couple of statements for it to work, although that did not give an error message.

Below is a script that I have tested (for player one only.) You will need to add scripts for the other 7 regions on the end, but that is simple. You will also have to place the 8 regions on the map in front of the towns (and place obstacles so that the player will have to pass through the regions.

This script will give the artifacts to whatever heroe leaves town first as long as he is not the starting heroe, which is what you said you wanted the script to do.

----------------------------
--declare global variables--
----------------------------
newHeroOne = 0;
newHeroTwo = 0;
newHeroThree = 0;
newHeroFour = 0;
newHeroFive = 0;
newHeroSix = 0;
newHeroSeven = 0;
newHeroEight = 0;

dummylist = GetPlayerHeroes (PLAYER_1);
heroeOneStart = dummylist[0]; --dummy value
heroeTwoStart = dummylist[0]; --dummy value
heroeThreeStart = dummylist[0]; --dummy value
heroeFourStart = dummylist[0]; --dummy value
heroeFiveStart = dummylist[0]; --dummy value
heroeSixStart = dummylist[0]; --dummy value
heroeSevenStart = dummylist[0]; --dummy value
heroeEightStart = dummylist[0]; --dummy value


----------------------------------------------------
--determine starting heroe and give him experience--
----------------------------------------------------

for i = 1, 8, 1 do --do for player (this assumes eight players)
ChangeHeroStat (GetPlayerHeroes(i)[0], STAT_EXPERIENCE, 8000);
MakeHeroReturnToTavernAfterDeath(GetPlayerHeroes(i)[0], true, 1 );
if GetCurrentPlayer () == PLAYER_1 then
dummylist = GetPlayerHeroes (PLAYER_1);
heroeOneStart = dummylist[0];

end;
if GetCurrentPlayer () == PLAYER_2 then
dummylist = GetPlayerHeroes (PLAYER_1);
heroeTwoStart = dummylist[0];
end;
if GetCurrentPlayer () == PLAYER_3 then
dummylist = GetPlayerHeroes (PLAYER_1);
heroeThreeStart = dummylist[0];
end;
if GetCurrentPlayer () == PLAYER_4 then
dummylist = GetPlayerHeroes (PLAYER_1);
heroeFourStart = dummylist[0];
end;
if GetCurrentPlayer () == PLAYER_5 then
dummylist = GetPlayerHeroes (PLAYER_1);
heroeFiveStart = dummylist[0];
end;
if GetCurrentPlayer () == PLAYER_6 then
dummylist = GetPlayerHeroes (PLAYER_1);
heroeSixStart = dummylist[0];
end;
if GetCurrentPlayer () == PLAYER_7 then
dummylist = GetPlayerHeroes (PLAYER_1);
heroeSevenStart = dummylist[0];
end;
if GetCurrentPlayer () == PLAYER_8 then
dummylist = GetPlayerHeroes (PLAYER_1);
heroeEightStart = dummylist[0];
end;

end;



--------------------------------------------------------------
--this function will be called by regions in front of towns.--
--It gives artifacts to the first heroe to leave town who is--
--not the starting heroe.-------------------------------------
--------------------------------------------------------------

function heroIsBorn (heroname)
-- LevelUpHero(heroname); --debug script

if GetCurrentPlayer () == PLAYER_1 and newHeroOne == 0 then --no artifacts given yet
if heroname ~= heroeOneStart then
newHeroOne = 1; --set flag for artifacts given
GiveArtefact(heroname, 34, 1);
GiveArtefact(heroname, 35, 1);
end;
end;
if GetCurrentPlayer () == PLAYER_2 and newHeroTwo == 0 then
if heroname ~= heroeTwoStart then
newHeroTwo = 1;
GiveArtefact(heroname, 34, 1);
GiveArtefact(heroname, 35, 1);
end;
end;
if GetCurrentPlayer () == PLAYER_3 and newHeroThree == 0 then
if heroname ~= heroeThreeStart then
newHeroThree = 1;
GiveArtefact(heroname, 34, 1);
GiveArtefact(heroname, 35, 1);
end;
end;
if GetCurrentPlayer () == PLAYER_4 and newHeroFour == 0 then
if heroname ~= heroeFourStart then
newHeroFour = 1;
GiveArtefact(heroname, 34, 1);
GiveArtefact(heroname, 35, 1);
end;
end;
if GetCurrentPlayer () == PLAYER_5 and newHeroFive == 0 then
if heroname ~= heroeFiveStart then
newHeroFive = 1;
GiveArtefact(heroname, 34, 1);
GiveArtefact(heroname, 35, 1);
end;
end;
if GetCurrentPlayer () == PLAYER_6 and newHeroSix == 0 then
if heroname ~= heroeSixStart then
newHeroSix = 1;
GiveArtefact(heroname, 34, 1);
GiveArtefact(heroname, 35, 1);
end;
end;
if GetCurrentPlayer () == PLAYER_7 and newHeroSeven == 0 then
if heroname ~= heroeSevenStart then
newHeroSeven = 1;
GiveArtefact(heroname, 34, 1);
GiveArtefact(heroname, 35, 1);
end;
end;
if GetCurrentPlayer () == PLAYER_8 and newHeroEight == 0 then
if heroname ~= heroeEightStart then
newHeroEight = 1;
GiveArtefact(heroname, 34, 1);
GiveArtefact(heroname, 35, 1);
end;
end;
end;


-----------------------------
--Regions in front of towns--
-----------------------------
function TownOneFront(heroname)

heroIsBorn(heroname); --call the function that gives artifacts

Trigger( REGION_ENTER_AND_STOP_TRIGGER, "rgnTownOneFront");
end;
Trigger( REGION_ENTER_AND_STOP_TRIGGER, "rgnTownOneFront", "TownOneFront");
Frodo: "I wish the ring had never come to me. I wish none of this had happened."
Gandalf: "So do all who live to see such times but that is not for them to decide. All we have to decide is what to do with the time that is given to us."

GohozoqPohobo
Leprechaun
Leprechaun
Posts: 26
Joined: 30 Sep 2007

Unread postby GohozoqPohobo » 13 Nov 2007, 03:19

I'm still getting

Function MakeHeroReturnToTaverernAfterDeath not defined, line 30.
and
Function TownOneFront not defined, line 142

Beyond that...
I've placed the regions you mentioned. As far as the obstacles, can I not just make the region large enough that it's impossible to leave the castle without passing through?
Also, I'm not certain how to replicate the code for the other regions, partly because I can't get the first one to work. I think I can see how to repeat the pattern, but I can't really be certain because they all generate the same errors.

By the way, I really appreciate all your help.

User avatar
Grumpy Old Wizard
Round Table Knight
Round Table Knight
Posts: 2205
Joined: 06 Jan 2006
Location: Tower Grump

Unread postby Grumpy Old Wizard » 13 Nov 2007, 04:13

GohozoqPohobo wrote:I'm still getting

Function MakeHeroReturnToTaverernAfterDeath not defined, line 30.
and
Function TownOneFront not defined, line 142

Beyond that...
I've placed the regions you mentioned. As far as the obstacles, can I not just make the region large enough that it's impossible to leave the castle without passing through?
Also, I'm not certain how to replicate the code for the other regions, partly because I can't get the first one to work. I think I can see how to repeat the pattern, but I can't really be certain because they all generate the same errors.

By the way, I really appreciate all your help.
You will get error messages all the time from Check Script or the console that mean nothing at all. Ignore them. I tested the code I posted. It works if you copy and paste it exactly as I posted it.

I recommend placing regions so that they are a step or 2 from the town so the heroe has to step into the region. You can easily use trees, bushes, or masks to make it so the heroe has to enter the region.

You do have to place a region in front of the first town and name it rgnTownOneFront for the first town.

For the code for the other regions, it would be exactly almost the same as the code for the the first region.

For example, to keep the script consistant, I would name the region in front of the second player's town rgnTownTwoFront. Then the code would be:
function TownTwoFront(heroname)

heroIsBorn(heroname); --call the function that gives artifacts

Trigger( REGION_ENTER_AND_STOP_TRIGGER, "rgnTownTwoFront");
end;
Trigger( REGION_ENTER_AND_STOP_TRIGGER, "rgnTownTwoFront", "TownTwoFront");
As you see, you only have to replace the region name (twice) and the function name twice. Other than that the code is identical. You will notice that I always name regions beginning with rgn to make it easier for me to keep track of things. rgnTownOneFront became rgnTownTwoFront and TownOneFront (the function name) became TownTwoFront.

All the code for the regions is doing is calling up the heroIsBorn function, which already has all the code to give the artifacts to the correct heroe.

GOW
Frodo: "I wish the ring had never come to me. I wish none of this had happened."
Gandalf: "So do all who live to see such times but that is not for them to decide. All we have to decide is what to do with the time that is given to us."

GohozoqPohobo
Leprechaun
Leprechaun
Posts: 26
Joined: 30 Sep 2007

Unread postby GohozoqPohobo » 13 Nov 2007, 05:17

It's working perfectly for the first player, and for that I am thankful.
With a little more work, I got it working for everyone.
Thank you very much.
The last questions I have are these:
How do I post messages to the screen to go along with the events?
Can I bind artifacts in such a way that the hero does not lose them when they die (but in fact maintains them even after death to the tavern).

User avatar
Grumpy Old Wizard
Round Table Knight
Round Table Knight
Posts: 2205
Joined: 06 Jan 2006
Location: Tower Grump

Unread postby Grumpy Old Wizard » 13 Nov 2007, 07:01

GohozoqPohobo wrote:It's working perfectly for the first player, and for that I am thankful.
With a little more work, I got it working for everyone.
Thank you very much.
The last questions I have are these:
How do I post messages to the screen to go along with the events?
Can I bind artifacts in such a way that the hero does not lose them when they die (but in fact maintains them even after death to the tavern).

For messages, I'll use an example from my Shadow Dreams map.

The first line of code in the script of that map is a line that assigns the path of messages for the map to a variable I named path. It is useful to avoid typing the same thing over and over. Replace Shadow Dreams with the name of your map.
path = "Maps/SingleMissions/Shadow Dreams/"; -- shorthand
MessageBox is the command that displays messages. Here is an example of 2 messages. In the first message I did not use the path variable as a shortcut. In the second messge I did.
MessageBox("Maps/SingleMissions/Shadow Dreams/Intro1.txt");

MessageBox(path.."Intro2.txt");
Those 2 commands display the messges Intro1.txt and Intro2.txt.

In order to make a text for a message, you need to do the following:
1) Click on View on the toolbar, then Map Properties Tree.
2) Click on the + in front of Resources to expand the menue. Click on the + in front of SavesFileNames if there is one.
3) Right Click on SavesFileNames and chose Add. Click on the + in front of the file that you just created.
4) Click to the right of SaveFileNameFileRef. Click on the New button that appears. Name the file, click Ok, and type whatever you want in the text file and click OK.

Whatever you typed for the name of the file is what you use in the MessageBox command. Be sure to put quotes as I did in the 2 examples above.

I know that you can bind artifacts to a heroe so he can't trade them with the give artifact command
GiveArtefact(heroname, artefactID, 1);
I don't know if that also prevents the heroe from losing the artifact if he loses the battle. Test it out and see.

You could use the SetHeroLootable command to prevent the heroefrom losing any of his artifacts if he is defeated.
SetHeroLootable(heroName, enable);
GOW
Frodo: "I wish the ring had never come to me. I wish none of this had happened."
Gandalf: "So do all who live to see such times but that is not for them to decide. All we have to decide is what to do with the time that is given to us."


Return to “Mapmaking Guild”

Who is online

Users browsing this forum: No registered users and 2 guests