Are you, in fact, a pregnant lady who lives in the apartment next door to Superdeath's parents? - Commodore

Create an account  

 
Modding Discussion Thread

(July 16th, 2024, 02:08)Suppanut Wrote:
(July 15th, 2024, 04:09)GMBarak Wrote: Hey,

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.  popcorn
Reply

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).
Reply

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; }
}

} ENDLP B=1;

DEBUGLOG "OET: W = " + STRS(W);
DEBUGLOG "HOMERACE: " + STRS(HOMERACE(W));

And here is AICustomWizard.cas
Code:
:
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.

Wizard templates are the following
1 - Mono Nature
2 - Mono Sorcery
3 - Mono Chaos
4 - Mono Life
5 - Mono Death
6 - Nature/Sorcery
7 - Nature/Chaos
8 - Nature/Life
9 - Nature/Death
10 - Sorcery/Chaos
11 - Sorcery/Life
12 - Sorcery/Death
13 - Chaos/Life
14 - Chaos/Death
15 - Life/Death
:

HAVENATURE=0;
HAVESORCERY=0;
HAVECHAOS=0;
HAVELIFE=0;
HAVEDEATH=0;
MULTIREALM=0;

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; }

MULTIREALM=HAVENATURE+HAVESORCERY+HAVECHAOS+HAVELIFE+HAVEDEATH;

: If retort is Warlord, wizard will never pick mono-Death template) :
IF (RETORT(W,Warlord)) %AND (TEMPLATE=5) THEN { REROLL=1; }

: If retort is Cult Leader, wizard will never pick mono-Sorcery template) :
IF (RETORT(W,CultLeader)) %AND (TEMPLATE=2) THEN { REROLL=1; }

: If retort is Conjurer, wizard will never pick mono-Life template) :
IF (RETORT(W,Conjurer)) %AND (TEMPLATE=4) THEN { REROLL=1; }

: Chance of specialist retort increase as number of books in main realm increase :
IF (RETORT(W,Specialist)) THEN { CALL "ISSPECIALIST"; }

  IF (TEMPLATE>6) THEN { CALL "ENDSPECIALIST"; }
   IF (TEMPLATE=1) %AND ((BOOKS(W,Nature))>8) %AND (((BOOKS(W,Sorcery))+(BOOKS(W,Chaos))+(BOOKS(W,Life))+(BOOKS(W,Death)))=0) THEN {
    SETRETORT(W,Specialist,1);
    SETBOOK(W,Nature,(BOOKS(W,Nature)-1));
    CALL "ENDSPECIALIST";
   }
   IF (TEMPLATE=2) %AND ((BOOKS(W,Sorcery))>8) %AND (((BOOKS(W,Nature))+(BOOKS(W,Chaos))+(BOOKS(W,Life))+(BOOKS(W,Death)))=0) THEN {
    SETRETORT(W,Specialist,1);
    SETBOOK(W,Sorcery,(BOOKS(W,Sorcery)-1));
    CALL "ENDSPECIALIST";
   }
   IF (TEMPLATE=3) %AND ((BOOKS(W,Chaos))>8) %AND (((BOOKS(W,Nature))+(BOOKS(W,Sorcery))+(BOOKS(W,Life))+(BOOKS(W,Death)))=0) THEN {
    SETRETORT(W,Specialist,1);
    SETBOOK(W,Chaos,(BOOKS(W,Chaos)-1));
    CALL "ENDSPECIALIST";
   }
   IF (TEMPLATE=4) %AND ((BOOKS(W,Life))>8) %AND (((BOOKS(W,Nature))+(BOOKS(W,Sorcery))+(BOOKS(W,Chaos))+(BOOKS(W,Death)))=0) THEN {
    SETRETORT(W,Specialist,1);
    SETBOOK(W,Life,(BOOKS(W,Life)-1));
    CALL "ENDSPECIALIST";
   }
   IF (TEMPLATE=5) %AND ((BOOKS(W,Death))>8) %AND (((BOOKS(W,Nature))+(BOOKS(W,Sorcery))+(BOOKS(W,Chaos))+(BOOKS(W,Life)))=0) THEN {
    SETRETORT(W,Specialist,1);
    SETBOOK(W,Death,(BOOKS(W,Death)-1));
    CALL "ENDSPECIALIST";
   }

: If retort is Specialist, wizard will only using on mono realm template or has main realm not more than combination of others :
!ISSPECIALIST!

  IF ( (TEMPLATE>5)
   %OR ( (TEMPLATE=1) %AND ( (((BOOKS(W,Sorcery))+(BOOKS(W,Chaos))+(BOOKS(W,Life))+(BOOKS(W,Death)))>1) ) )
   %OR ( (TEMPLATE=2) %AND ( (((BOOKS(W,Nature))+(BOOKS(W,Chaos))+(BOOKS(W,Life))+(BOOKS(W,Death)))>1) ) )
   %OR ( (TEMPLATE=3) %AND ( (((BOOKS(W,Nature))+(BOOKS(W,Sorcery))+(BOOKS(W,Life))+(BOOKS(W,Death)))>1) ) )
   %OR ( (TEMPLATE=4) %AND ( (((BOOKS(W,Nature))+(BOOKS(W,Sorcery))+(BOOKS(W,Chaos))+(BOOKS(W,Death)))>1) ) )
   %OR ( (TEMPLATE=5) %AND ( (((BOOKS(W,Nature))+(BOOKS(W,Sorcery))+(BOOKS(W,Chaos))+(BOOKS(W,Life)))>1) ) ) )
  THEN { REROLL=1; }

!ENDSPECIALIST!

: 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";
     }
    }
   }

!ENDPROCURATOR!

!LESSTHANADVANCED!

REROLL=0;


Attached Files
.zip   CrashScripts.zip (Size: 2.88 KB / Downloads: 0)
Reply

Quick questions: is there any maximum number of picks for custom wizards? In principle, could it be 40? I tried once with 24 and it worked.
Reply

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".
Reply

(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.
Reply

(August 23rd, 2024, 09:14)Suppanut Wrote:
(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.
Reply

Thank you. This explains a lot about what really happens. I will look forward for GOTO command.
Reply

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.
Reply

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.
Reply



Forum Jump: