From watching the Hadriex birdmen gameplay on YouTube, it appears that the birdman Thunderbird unit is too OP, 3 lightning bolts for one unit appears too strong, looks equivalent to one of the strongest late game very rare summons.
just fyi, thanks!
He has his own thread on forum but I completely agree with you. Its value is almost exceed some very rare summons.
For the next version I reduced the number of bolts. Hopefully it didn't turn into a Thunderchicken.
Is there any way to ramp up monster rampage cost mid-game by script? I want to make monster rampage get much worse and make node start spawning monster again when someone casting Spell of Mastery (as magic scream up as some one try to rape it).
I try to implement Call function into AIRace.cas and AICustomWizard.cas but they crash without identify any error. I could not find out why it crash so I post here in case people could tell why they crash.
AIRace.cas
Code:
: This script picks the starting city race for AI players.
Input, W is thw wizard making the choice.
Output, RACE must contain the selected race. :
LOOP {
B=1;
IF RETORT(W,MYRRAN) THEN { CALL "ISMYRRAN"; }
IF RETORT(W,TACTICIAN) %AND (BOOKS(W,Nature)<4) THEN { CALL "ARCANIANTACTICIAN"; }
: Cultleader :
IF (RETORT(W,CULTLEADER)) THEN {
ROLL=RND(7);
IF ROLL=0 THEN { RACE=RCOrc; CALL "PICKED"; }
IF ROLL=1 THEN { RACE=RCHalfling; CALL "PICKED"; }
IF ROLL=2 THEN { RACE=RCHighElf; CALL "PICKED"; }
IF ROLL=3 THEN { RACE=RCHighMen; CALL "PICKED"; }
IF ROLL=4 THEN { RACE=RCLizard; CALL "PICKED"; }
IF ROLL=5 THEN { RACE=RCNomad; CALL "PICKED"; }
IF ROLL=6 THEN { RACE=RCHawkmen; CALL "PICKED"; }
}
: not Cultleader:
RACE=RANDOMARCANUSRACE(0); CALL "PICKED"; }
!ARCANIANTACTICIAN!
: Half-track tactician with Cultleader :
IF RETORT(W,CULTLEADER) THEN {
ROLL=RND(2);
IF ROLL=0 THEN { RACE=RCHighElf; CALL "PICKED"; }
IF ROLL=1 THEN { RACE=RCLizard; CALL "PICKED"; }
}
: Half-track tactician without Cultleader :
ROLL=RND(4);
IF ROLL=0 THEN { RACE=RCHighElf; CALL "PICKED"; }
IF ROLL=1 THEN { RACE=RCLizard; CALL "PICKED"; }
IF ROLL=2 THEN { RACE=RCBarbarian; CALL "PICKED"; }
IF ROLL=3 THEN { RACE=RCGnoll; CALL "PICKED"; }
}
!ISMYRRAN!
IF RETORT(W,TACTICIAN) %AND (BOOKS(W,Nature)<4) THEN { CALL "MYRRANTACTICIAN"; }
: Myrran Cultleader :
IF RETORT(W,CULTLEADER) THEN { CALL "MYRRANCULTLEADER"; }
: Myrran but not cultleader :
IF (BOOKS(W,Sorcery)>6) THEN { RACE=RANDOMMYRRANRACE(0); CALL "PICKED"; }
ROLL=RND(5);
IF ROLL=0 THEN { RACE=RCBeastmen; CALL "PICKED"; }
IF ROLL=1 THEN { RACE=RCDarkElf; CALL "PICKED"; }
IF ROLL=2 THEN { RACE=RCDraconian; CALL "PICKED"; }
IF ROLL=3 THEN { RACE=RCTroll; CALL "PICKED"; }
IF ROLL=4 THEN { RACE=RCRakhshasa; CALL "PICKED"; }
!MYRRANCULTLEADER!
: Myrran Cultleader :
ROLL=RND(5);
IF ROLL=0 THEN { RACE=RCBeastmen; CALL "PICKED"; }
IF ROLL=1 THEN { RACE=RCDarkElf; CALL "PICKED"; }
IF ROLL=2 THEN { RACE=RCDraconian; CALL "PICKED"; }
IF ROLL=3 THEN { RACE=RCRakhshasa; CALL "PICKED"; }
IF ROLL=4 THEN {
IF (BOOKS(W,Sorcery)<7) THEN { RACE=RCDwarf; CALL "PICKED"; }
ROLL=RND(4);
IF ROLL=0 THEN { RACE=RCBeastmen; CALL "PICKED"; }
IF ROLL=1 THEN { RACE=RCDarkElf; CALL "PICKED"; }
IF ROLL=2 THEN { RACE=RCDraconian; CALL "PICKED"; }
IF ROLL=3 THEN { RACE=RCRakhshasa; CALL "PICKED"; }
}
!MYRRANTACTICIAN!
ROLL=RND(2);
IF ROLL=0 THEN { RACE=RCRakhshasa; CALL "PICKED"; }
IF ROLL=1 THEN {
IF (BOOKS(W,Sorcery)<7) THEN { RACE=RCDwarf; CALL "PICKED"; } ELSE { RACE=RCRakhshasa; CALL "PICKED"; }
}
!PICKED!
IF ((RACE=RCBarbarian) %OR (RACE=RCGnoll))
%AND ((PERSONALITY(W)=PEACEFUL) %OR (PERSONALITY(W)=LAWFUL)) THEN { B=0; }
IF (RACE=RCHalfling) THEN {
B=0;
IF (PERSONALITY(W)=PEACEFUL) THEN { B=1; }
IF ((PERSONALITY(W)=LAWFUL) %OR (RETORT(W,Charismatic)))
%AND ((%N(OBJECTIVE(W)=MILITARIST)) %AND (%N(OBJECTIVE(W)=EXPANSIONIST))) THEN { B=1; }
}
IF (RACE=RCHawkmen) THEN {
B=0;
IF (PERSONALITY(W)=LAWFUL) THEN { B=1; }
}
:
INPUT
W = The ID of the wizard that was rolled
TEMPLATE = The template identifier of the wizard that was rolled
OUTPUT
REROLL - If set to 1, the wizard is discarded and a new one will be generated. Otherwise the wizard is accepted.
Use this script to manipulate the probability of generating various AI opponents.
Some examples below
IF RETORT(W,WARLORD) THEN { REROLL=1; }
Will result in the game never generating a Warlord opponent.
IF (RETORT(W,ALCHEMIST)) %AND (RANDOM(100)>=50) THEN { REROLL=1; }
Will result in generating wizards with Alchemist half as often.
By accessing wizard data below W you can even restrict what the current wizard is
allowed to roll based on what other wizards are already generated for the game.
Please keep in mind that a very high chance of rerolling can result in wizard generation
taking a large amount of time to execute.
So please avoid defining rules that only allow like 1 out of a million generated wizard to be accepted.
Additionally, you can overwrite the already generated data by setting the books and retorts directly,
using the Setretort and Setbook commands instead of rerolling. You can use that to completely
override the default way of generating wizards based on templates.
However in that case you MUST handle every book and retort in this script, except the MYRRAN retort,
which shouldn't be changed otherwise the condition to have the intended amount of Myrran wizards
will not be fulfilled and the game will be stuck in an endless loop.
IF (DIFFICULTY()<DiffAdvanced) THEN { CALL "LESSTHANADVANCED"; }
IF (BOOKS(W,Nature)>0) THEN { HAVENATURE=1; }
IF (BOOKS(W,Sorcery)>0) THEN { HAVESORCERY=1; }
IF (BOOKS(W,Chaos)>0) THEN { HAVECHAOS=1; }
IF (BOOKS(W,Life)>0) THEN { HAVELIFE=1; }
IF (BOOKS(W,Death)>0) THEN { HAVEDEATH=1; }
: If have more than 2 realms but not have procurator retort, then there is 50% chance to reroll :
IF (MULTIREALM<3) THEN { CALL "ENDPROCURATOR"; }
IF (RETORT(W,Procurator)) THEN { CALL "ENDPROCURATOR"; }
IF (RND(60/MULTIREALM)<12) THEN {
SETRETORT(W,Procurator,1);
IF (TEMPLATE=1) THEN {
SETBOOK(W,Nature,(BOOKS(W,Nature)-1));
CALL "ENDPROCURATOR";
}
IF (TEMPLATE=2) THEN {
SETBOOK(W,Sorcery,(BOOKS(W,Sorcery)-1));
CALL "ENDPROCURATOR";
}
IF (TEMPLATE=3) THEN {
SETBOOK(W,Chaos,(BOOKS(W,Chaos)-1));
CALL "ENDPROCURATOR";
}
IF (TEMPLATE=4) THEN {
SETBOOK(W,Life,(BOOKS(W,Life)-1));
CALL "ENDPROCURATOR";
}
IF (TEMPLATE=5) THEN {
SETBOOK(W,Death,(BOOKS(W,Death)-1));
CALL "ENDPROCURATOR";
}
IF (TEMPLATE=6) THEN {
IF ((BOOKS(W,Nature))>(BOOKS(W,Sorcery))) THEN {
SETBOOK(W,Nature,(BOOKS(W,Nature)-1));
CALL "ENDPROCURATOR";
} ELSE {
SETBOOK(W,Sorcery,(BOOKS(W,Sorcery)-1));
CALL "ENDPROCURATOR";
}
}
IF (TEMPLATE=7) THEN {
IF ((BOOKS(W,Nature))>(BOOKS(W,Chaos))) THEN {
SETBOOK(W,Nature,(BOOKS(W,Nature)-1));
CALL "ENDPROCURATOR";
} ELSE {
SETBOOK(W,Chaos,(BOOKS(W,Chaos)-1));
CALL "ENDPROCURATOR";
}
}
IF (TEMPLATE=8) THEN {
IF ((BOOKS(W,Nature))>(BOOKS(W,Life))) THEN {
SETBOOK(W,Nature,(BOOKS(W,Nature)-1));
CALL "ENDPROCURATOR";
} ELSE {
SETBOOK(W,Life,(BOOKS(W,Life)-1));
CALL "ENDPROCURATOR";
}
}
IF (TEMPLATE=9) THEN {
IF ((BOOKS(W,Nature))>(BOOKS(W,Death))) THEN {
SETBOOK(W,Nature,(BOOKS(W,Nature)-1));
CALL "ENDPROCURATOR";
} ELSE {
SETBOOK(W,Death,(BOOKS(W,Death)-1));
CALL "ENDPROCURATOR";
}
}
IF (TEMPLATE=10) THEN {
IF ((BOOKS(W,Sorcery))>(BOOKS(W,Chaos))) THEN {
SETBOOK(W,Sorcery,(BOOKS(W,Sorcery)-1));
CALL "ENDPROCURATOR";
} ELSE {
SETBOOK(W,Chaos,(BOOKS(W,Chaos)-1));
CALL "ENDPROCURATOR";
}
}
IF (TEMPLATE=11) THEN {
IF ((BOOKS(W,Sorcery))>(BOOKS(W,Life))) THEN {
SETBOOK(W,Sorcery,(BOOKS(W,Sorcery)-1));
CALL "ENDPROCURATOR";
} ELSE {
SETBOOK(W,Life,(BOOKS(W,Life)-1));
CALL "ENDPROCURATOR";
}
}
IF (TEMPLATE=12) THEN {
IF ((BOOKS(W,Sorcery))>(BOOKS(W,Death))) THEN {
SETBOOK(W,Sorcery,(BOOKS(W,Sorcery)-1));
CALL "ENDPROCURATOR";
} ELSE {
SETBOOK(W,Death,(BOOKS(W,Death)-1));
CALL "ENDPROCURATOR";
}
}
IF (TEMPLATE=13) THEN {
IF ((BOOKS(W,Chaos))>(BOOKS(W,Life))) THEN {
SETBOOK(W,Chaos,(BOOKS(W,Chaos)-1));
CALL "ENDPROCURATOR";
} ELSE {
SETBOOK(W,Life,(BOOKS(W,Life)-1));
CALL "ENDPROCURATOR";
}
}
IF (TEMPLATE=14) THEN {
IF ((BOOKS(W,Chaos))>(BOOKS(W,Death))) THEN {
SETBOOK(W,Chaos,(BOOKS(W,Chaos)-1));
CALL "ENDPROCURATOR";
} ELSE {
SETBOOK(W,Death,(BOOKS(W,Death)-1));
CALL "ENDPROCURATOR";
}
}
IF (TEMPLATE=15) THEN {
IF ((BOOKS(W,Life))>(BOOKS(W,Death))) THEN {
SETBOOK(W,Life,(BOOKS(W,Life)-1));
CALL "ENDPROCURATOR";
} ELSE {
SETBOOK(W,Death,(BOOKS(W,Death)-1));
CALL "ENDPROCURATOR";
}
}
}
Jump to the label that matches the string and store the current position.
You can only jump to labels declared in the same .CAS file. Jumping/Calling between different script files is not supported.
You use this to call a subroutine. Functions are not directly supported, to return a value from a subroutine call, you must set it to a global variable.
RETURN
Jump back to the last stored processing position from an executed CALL statement.
Local variables created inside this subroutine will be deleted.
Not quite sure why it would crash though but that's definitely a problem. Maybe the engine cannot handle the script terminating without returning from a "call".
(August 23rd, 2024, 07:02)Seravy Wrote: I don't see any "Return" in that code?
Quote:CALL string
Jump to the label that matches the string and store the current position.
You can only jump to labels declared in the same .CAS file. Jumping/Calling between different script files is not supported.
You use this to call a subroutine. Functions are not directly supported, to return a value from a subroutine call, you must set it to a global variable.
RETURN
Jump back to the last stored processing position from an executed CALL statement.
Local variables created inside this subroutine will be deleted.
Not quite sure why it would crash though but that's definitely a problem. Maybe the engine cannot handle the script terminating without returning from a "call".
Normally they don't need return, I so often using Call function to skip part of the script rather than repeat some part of the script.
(August 23rd, 2024, 07:02)Seravy Wrote: I don't see any "Return" in that code?
Quote:CALL string
Jump to the label that matches the string and store the current position.
You can only jump to labels declared in the same .CAS file. Jumping/Calling between different script files is not supported.
You use this to call a subroutine. Functions are not directly supported, to return a value from a subroutine call, you must set it to a global variable.
RETURN
Jump back to the last stored processing position from an executed CALL statement.
Local variables created inside this subroutine will be deleted.
Not quite sure why it would crash though but that's definitely a problem. Maybe the engine cannot handle the script terminating without returning from a "call".
Normally they don't need return, I so often using Call function to skip part of the script rather than repeat some part of the script.
Hmmm sounds like I should add "GOTO" in the next update.
Using Call without a Return might or might not be safe. If the game runs a script during another script at any time (for example if there is a script function to ask data that requires a script to calculate), it will crash. However I'm 80% certain the game doesn't do that, and it was planned as a future possible feature.
Either way I don't recommend ever doing that.
Also if you use Call without returning in a way that creates a loop (two parts jumping to each other until some escape condition stops that), you can end up with the equivalent of a stack overflow.
Do modded units obey the checks for being from the right plane when offered as mercenaries before the towers are opened, or anyone has learnt Plane Shift? I recall that they didn't, but I want to be perfectly sure.
What is the ID of unit summon in combat? I try to modified them with COSpell.cas upon casting using MAXUNIT() as unit ID but not success so far.
Edited: after dig further I found problem to be something else entirely, COSpell.cas does not load. I try to make script write debug but it not appear on log file. try other effect of spell or just try to make it record caster unit's ID on Master variable and result still stay 0 (no change). So this could only mean one thing COSpell.cas does not load in version 1.5.7 for some reason.
Edited: after testing further COSpell.cas does not working for combat summon spells only, not sure if this is a bug or not.