This mod aims to implement proper spell slot restrictions for Specialist mages, forcing them to choose a spell from their school for their bonus spell slots.
Weidu should be able to install it so long as the section dealing with the Mage Spellbook hasn't already been altered. It uses REPLACE_TEXTUALLY for all its changes, if there is a better way I am open to suggestions.
The marker effects for this are applied to specialists at level 1 through the CLAB, so games already in progress will require force-casting a spell on existing specialists through the console. This marker effect will remain if the mod is uninstalled, but does nothing by itself and will not affect gameplay otherwise. This marker is a dummy sequencer, so the Sequencer Active portrait Icon will always be in effect, and it will show up as a blank line in the active Contingencies list.
It needs to be installed after any mods that add or alter Mage spells or creatures with specialist kits, so they can receive proper recognition.
ConsoleCast:
C:Eval("ActionOverride(Myself,ReallyForceSpellRES(\"MSCHOOL\",Msyelf))")
Only the 8 specialist mage kits will receive the marker, it will have no affect on others, including Wildmages and Mod-added kits.
The second component causes the extra spells slots from Edwin's Amulet to be treated the same way, requiring Conjuration Spells be put in them. The effect added to the Amulet can be added to anything, using "MSCHOOL#" as the resource, where # is the Spell School(as assigned to spells), forcing an extra slot of every spell level to go to that spell school.
Specialist School spells and slots are identified by a simple "rectangle 0" border:
Manual Editing:
Comment out "INCLUDE ~%MOD_FOLDER%\UIMENU.tpa~" in the "UIMENU.tpa" file.
Replace these two functions:
function magePageInfo()
if bookMode == 0 then -- Regular
if characters[id].hasSorcererBook then
return t("SPELLS_CAN_CAST_LABEL") .. ": " .. characters[id].mageDetails[currentSpellLevel].slotsRemaining .. "/" .. characters[id].mageDetails[currentSpellLevel].maxMemorized
else
local num = 0 if #specialistSlot > 0 then num = #bottomSpells + #specialistSlot else num = #bottomSpells end
return t("MEMORIZED_LABEL") .. ": " .. #bottomSpells .. "/" .. characters[id].mageDetails[currentSpellLevel].maxMemorized
end
elseif bookMode == 1 then -- Sequencer/Contingency
return t("SPELLS_LABEL") .. " :" .. #bottomSpells .. "/" .. #bottomSpellsPlaceHolder
end
return ""
end
function refreshMageBook()
if currentSpellLevel == nil then
currentSpellLevel = 1
end
if bookMode == 0 then
if characters[id].hasMageBook then
bookSpells = characters[id].mageSpells[currentSpellLevel]
newBottomSpells = filterMemorizedMageSpells()
if showMageMemorizationFlash == true then
createMageMemorizationSparkle(0,0,36,36,"memorizedListMage", findFirstDifferenceInSpellList(bottomSpells, newBottomSpells))
showMageMemorizationFlash = false
end
bottomSpells = newBottomSpells
getSpecialistSlot()
bottomSpellsPlaceHolder = makeBlankTable(characters[id].mageDetails[currentSpellLevel].maxMemorized)
for index = 1, #currentSchool , 1 do
table.remove (bottomSpellsPlaceHolder, 1)
end
else
bookSpells = characters[id].mageSpells[currentSpellLevel]
bottomSpells = {}
bottomSpellsPlaceHolder = {}
end
elseif bookMode == 1 then
bookSpells = filterContingencyMageSpells()
bottomSpells = sequencerSpells
bottomSpellsPlaceHolder = makeBlankTable(contingencyMaxSpells)
contingencyDescription = mageBookStrings[contingencyResRef].tip
end
end
and all of menu 'MAGE':
menu
{
name 'MAGE'
align center center
greyscale lua "mageBookEnabled == false"
modal lua "bookMode == 1"
onopen "
specialistBookFilter()
showMageMemorizationFlash = false
mgpage = nil
setMageBookLevel(1)
if showContingency then
Infinity_SetArea('bookListMage', nil, 374, nil, 200)
Infinity_SetArea('bookDescription', nil, 374, nil, 200)
else
Infinity_SetArea('bookListMage', nil, 174, nil, 400)
Infinity_SetArea('bookDescription', nil, 174, nil, 400)
end
if bookMode == 1 then
contingencyDescription = mageBookStrings[contingencyResRef].tip
end
currentContingencyCondition = 0
currentContingencyTarget = 0
currentAnimationID = 1
updateCounterMemorizationSparkles = 1
"
onclose "
"
button
{
enabled "CurrentlyInGame()"
on escape
action
"
--Return to world screen on escape
e:SelectEngine(worldScreen)
"
}
template
{
label
{
enabled "showMemorizationSparkle(instanceId)"
ignoreEvents
area 0 0 45 42
bam "FLASHBR"
usealpha lua "true"
frame lua "memorizationFlashes[instanceId][2]"
align center center
}
name "TEMPLATE_mageMemorizationSparkle"
}
label
{
area 0 0 864 710
mosaic "GUIMGB2"
}
label
{
area 82 10 700 44
text lua "mageBookTitle()"
text style "title"
}
label
{
area 210 59 446 30
text lua "mageBookAction()"
text style "label"
}
button
{
area 168 110 54 54
bam GUIPRTC
highlightgroup mgpage
sequence 0
enabled "maxMagePage > 0"
action "setMageBookLevel(1)"
}
button
{
area 227 110 54 54
bam GUIPRTC
highlightgroup mgpage
sequence 1
enabled "maxMagePage > 1"
action "setMageBookLevel(2)"
}
button
{
area 286 110 54 54
bam GUIPRTC
highlightgroup mgpage
sequence 2
enabled "maxMagePage > 2"
action "setMageBookLevel(3)"
}
button
{
area 345 110 54 54
bam GUIPRTC
highlightgroup mgpage
sequence 3
enabled "maxMagePage > 3"
action "setMageBookLevel(4)"
}
button
{
area 404 110 54 54
bam GUIPRTC
highlightgroup mgpage
sequence 4
enabled "maxMagePage > 4"
action "setMageBookLevel(5)"
}
button
{
area 464 110 54 54
bam GUIPRTC
highlightgroup mgpage
sequence 5
enabled "maxMagePage > 5"
action "setMageBookLevel(6)"
}
button
{
area 523 110 54 54
bam GUIPRTC
highlightgroup mgpage
sequence 6
enabled "maxMagePage > 6"
action "setMageBookLevel(7)"
}
button
{
area 583 110 54 54
bam GUIPRTC
highlightgroup mgpage
sequence 7
enabled "maxMagePage > 7"
action "setMageBookLevel(8)"
}
button
{
area 644 110 54 54
bam GUIPRTC
highlightgroup mgpage
sequence 8
enabled "maxMagePage > 8"
action "setMageBookLevel(9)"
}
list
{
column
{
width 15
label
{
area 0 0 -1 -1
bam lua "bookSpells[rowNumber].icon"
enabled "specialistIcon(0)"
align center center
}
label { area 0 0 -1 -1 bam lua "bookSpells[rowNumber].icon" align center center enabled "specialistIcon(1)" rectangle 0}
}
column
{
width 85
label
{
area 0 0 -1 -1
text lua "Infinity_FetchString( bookSpells[rowNumber].name)"
text style "normal_parchment"
text align left center
}
}
area 94 174 316 400
name "bookListMage"
rowheight 40
table "bookSpells"
var currentBookSpell
scrollbar 'GUISCRC'
action
"
contingencyDescription = 0
if cellNumber == 1 then
if bookMode == 0 then
if #bottomSpells < #bottomSpellsPlaceHolder or SpecialistMemorize() then
createMageMemorizationSparkle(1, 0, 40, 40, 'bookListMage', -1)
Infinity_PlaySound('GAM_24')
showMageMemorizationFlash = true
mageScreen:MemorizeSpell( bookSpells[currentBookSpell].level, bookSpells[currentBookSpell].index )
end
elseif bookMode == 1 and #bottomSpells < #bottomSpellsPlaceHolder then
mageScreen:SequenceSpell( bookSpells[currentBookSpell].resref )
end
end
if lastCurrentBookSpell == currentBookSpell and cellNumber == 2 then
currentBookSpell = 0
contingencyDescription = mageBookStrings[contingencyResRef].tip
end
lastCurrentBookSpell = currentBookSpell
"
actionalt
"
if cellNumber == 1 and bookMode == 0 and characters[id].hasSorcererBook == false then
popup2Button(24485, 'REMOVE_BUTTON', function() mageScreen:EraseKnownSpell(bookSpells[currentBookSpell].resref) end)
end
"
}
label
{
area 100 178 314 192
rectangle 1
rectangle opacity 200
enabled "showContingency"
}
label
{
area 104 182 310 48
enabled "showContingency"
text "CONDITION_NORMAL"
text style "normal"
}
list
{
column
{
width 100
label
{
area 10 0 -1 -1
text lua "Infinity_FetchString( contingencyConditions[rowNumber].strref)"
text style "normal"
text align left center
}
}
area 104 224 310 141
enabled "showContingency"
rowheight 40
table "contingencyConditions"
var currentContingencyCondition
scrollbar 'GUISCRC'
action
"
contingencyDescription = contingencyConditions[currentContingencyCondition].desc
"
}
label
{
area 452 176 322 193
rectangle 1
rectangle opacity 200
enabled "showContingency"
}
label
{
area 464 176 310 48
enabled "showContingency"
text "TARGET_NORMAL"
text style "normal"
}
list
{
column
{
width 100
label
{
area 10 0 -1 -1
text lua "Infinity_FetchString( contingencyTargets[rowNumber].strref)"
text style "normal"
text align left center
}
}
area 458 228 316 141
enabled "showContingency"
rowheight 40
table "contingencyTargets"
var currentContingencyTarget
scrollbar 'GUISCRC'
action
"
contingencyDescription = contingencyTargets[currentContingencyTarget].desc
"
}
text
{
name "bookDescription"
area 452 174 316 400
text lua "mageBookDescription()"
text style "normal_parchment"
scrollbar 'GUISCRC'
}
list
{
column
{
width 100
label
{
area 0 0 -1 -1
bam "SPELFRMS"
sequence 0
align center center
}
}
area 72 658 714 36
enabled "(#bottomSpellsPlaceHolder ~= 0 or bookMode == 1) and isSpecialist(0)"
rowwidth 36
table "bottomSpellsPlaceHolder"
}
list { column { width 100 label { area 0 0 -1 -1 bam "SPELFRMS" sequence 0 align center center } } area 114 656 674 36 enabled "bookMode == 0 and isSpecialist(1, 1)" rowwidth 36 table "bottomSpellsPlaceHolder" }
list { column { width 100 label { area 0 0 -1 -1 bam "SPELFRMS" sequence 0 align center center } } area 150 656 638 36 enabled "bookMode == 0 and isSpecialist(2, 1)" rowwidth 36 table "bottomSpellsPlaceHolder" }
list { column { width 100 label { area 0 0 -1 -1 bam "SPELFRMS" sequence 0 align center center } } area 186 656 602 36 enabled "bookMode == 0 and isSpecialist(3, 1)" rowwidth 36 table "bottomSpellsPlaceHolder" }
list { column { width 100 label { area 0 0 -1 -1 bam "SPELFRMS" sequence 0 align center center } } area 222 656 566 36 enabled "bookMode == 0 and isSpecialist(4, 1)" rowwidth 36 table "bottomSpellsPlaceHolder" }
list { column { width 100 label { area 0 0 -1 -1 bam "SPELFRMS" sequence 0 align center center } } area 258 656 530 36 enabled "bookMode == 0 and isSpecialist(5, 1)" rowwidth 36 table "bottomSpellsPlaceHolder" }
list { column { width 100 label { area 0 0 -1 -1 bam "SPELFRMS" sequence 0 align center center } } area 294 656 494 36 enabled "bookMode == 0 and isSpecialist(6, 1)" rowwidth 36 table "bottomSpellsPlaceHolder" }
button { area 78 656 36 36 bam lua "specialistSlot[1].icon" align center center greyscale lua "specialistSlot[1].castable == 0" rectangle = 0
enabled "bookMode == 0 and isSpecialist(1, 0) and characters[id].mageDetails[currentSpellLevel].maxMemorized > 0"
action "showMageMemorizationFlash = false mageScreen:UnmemorizeSpell( specialistSlot[1].level, specialistSlot[1].memorizedIndex ) Infinity_PlaySound('GAM_44') refreshMageBook()"
}
button { area 114 656 36 36 bam lua "specialistSlot[2].icon" align center center greyscale lua "specialistSlot[2].castable == 0" rectangle = 0
enabled "bookMode == 0 and isSpecialist(2, 0) and characters[id].mageDetails[currentSpellLevel].maxMemorized > 0"
action "showMageMemorizationFlash = false mageScreen:UnmemorizeSpell( specialistSlot[2].level, specialistSlot[2].memorizedIndex ) Infinity_PlaySound('GAM_44') refreshMageBook()"
}
button { area 150 656 36 36 bam lua "specialistSlot[3].icon" align center center greyscale lua "specialistSlot[3].castable == 0" rectangle = 0
enabled "bookMode == 0 and isSpecialist(3, 0) and characters[id].mageDetails[currentSpellLevel].maxMemorized > 0"
action "showMageMemorizationFlash = false mageScreen:UnmemorizeSpell( specialistSlot[3].level, specialistSlot[3].memorizedIndex ) Infinity_PlaySound('GAM_44') refreshMageBook()"
}
button { area 186 656 36 36 bam lua "specialistSlot[4].icon" align center center greyscale lua "specialistSlot[4].castable == 0" rectangle = 0
enabled "bookMode == 0 and isSpecialist(4, 0) and characters[id].mageDetails[currentSpellLevel].maxMemorized > 0"
action "showMageMemorizationFlash = false mageScreen:UnmemorizeSpell( specialistSlot[4].level, specialistSlot[4].memorizedIndex ) Infinity_PlaySound('GAM_44') refreshMageBook()"
}
button { area 222 656 36 36 bam lua "specialistSlot[5].icon" align center center greyscale lua "specialistSlot[5].castable == 0" rectangle = 0
enabled "bookMode == 0 and isSpecialist(5, 0) and characters[id].mageDetails[currentSpellLevel].maxMemorized > 0"
action "showMageMemorizationFlash = false mageScreen:UnmemorizeSpell( specialistSlot[5].level, specialistSlot[5].memorizedIndex ) Infinity_PlaySound('GAM_44') refreshMageBook()"
}
button { area 258 656 36 36 bam lua "specialistSlot[6].icon" align center center greyscale lua "specialistSlot[6].castable == 0" rectangle = 0
enabled "bookMode == 0 and isSpecialist(6, 0) and characters[id].mageDetails[currentSpellLevel].maxMemorized > 0"
action "showMageMemorizationFlash = false mageScreen:UnmemorizeSpell( specialistSlot[6].level, specialistSlot[6].memorizedIndex ) Infinity_PlaySound('GAM_44') refreshMageBook()"
}
list { column { width 100 label { area 0 0 -1 -1 bam lua "bottomSpells[rowNumber].icon" align center center greyscale lua "bottomSpells[rowNumber].castable == 0" } }
area 114 656 638 36 name "memorizedListMage" enabled "bookMode == 0 and #bottomSpells ~= 0 and isSpecialist(1, 1)" rowwidth 36 table "bottomSpells" var currentBottomSpell
action" showMageMemorizationFlash = false mageScreen:UnmemorizeSpell( bottomSpells[currentBottomSpell].level, bottomSpells[currentBottomSpell].memorizedIndex ) Infinity_PlaySound('GAM_44') refreshMageBook()"
}
list { column { width 100 label { area 0 0 -1 -1 bam lua "bottomSpells[rowNumber].icon" align center center greyscale lua "bottomSpells[rowNumber].castable == 0" } }
area 150 656 602 36 name "memorizedListMage" enabled "bookMode == 0 and #bottomSpells ~= 0 and isSpecialist(2, 1)" rowwidth 36 table "bottomSpells" var currentBottomSpell
action" showMageMemorizationFlash = false mageScreen:UnmemorizeSpell( bottomSpells[currentBottomSpell].level, bottomSpells[currentBottomSpell].memorizedIndex ) Infinity_PlaySound('GAM_44') refreshMageBook()"
}
list { column { width 100 label { area 0 0 -1 -1 bam lua "bottomSpells[rowNumber].icon" align center center greyscale lua "bottomSpells[rowNumber].castable == 0" } }
area 186 656 566 36 name "memorizedListMage" enabled "bookMode == 0 and #bottomSpells ~= 0 and isSpecialist(3, 1)" rowwidth 36 table "bottomSpells" var currentBottomSpell
action" showMageMemorizationFlash = false mageScreen:UnmemorizeSpell( bottomSpells[currentBottomSpell].level, bottomSpells[currentBottomSpell].memorizedIndex ) Infinity_PlaySound('GAM_44') refreshMageBook()"
}
list { column { width 100 label { area 0 0 -1 -1 bam lua "bottomSpells[rowNumber].icon" align center center greyscale lua "bottomSpells[rowNumber].castable == 0" } }
area 222 656 530 36 name "memorizedListMage" enabled "bookMode == 0 and #bottomSpells ~= 0 and isSpecialist(4, 1)" rowwidth 36 table "bottomSpells" var currentBottomSpell
action" showMageMemorizationFlash = false mageScreen:UnmemorizeSpell( bottomSpells[currentBottomSpell].level, bottomSpells[currentBottomSpell].memorizedIndex ) Infinity_PlaySound('GAM_44') refreshMageBook()"
}
list { column { width 100 label { area 0 0 -1 -1 bam lua "bottomSpells[rowNumber].icon" align center center greyscale lua "bottomSpells[rowNumber].castable == 0" } }
area 258 656 494 36 name "memorizedListMage" enabled "bookMode == 0 and #bottomSpells ~= 0 and isSpecialist(5, 1)" rowwidth 36 table "bottomSpells" var currentBottomSpell
action" showMageMemorizationFlash = false mageScreen:UnmemorizeSpell( bottomSpells[currentBottomSpell].level, bottomSpells[currentBottomSpell].memorizedIndex ) Infinity_PlaySound('GAM_44') refreshMageBook()"
}
list { column { width 100 label { area 0 0 -1 -1 bam lua "bottomSpells[rowNumber].icon" align center center greyscale lua "bottomSpells[rowNumber].castable == 0" } }
area 294 656 458 36 name "memorizedListMage" enabled "bookMode == 0 and #bottomSpells ~= 0 and isSpecialist(6, 1)" rowwidth 36 table "bottomSpells" var currentBottomSpell
action" showMageMemorizationFlash = false mageScreen:UnmemorizeSpell( bottomSpells[currentBottomSpell].level, bottomSpells[currentBottomSpell].memorizedIndex ) Infinity_PlaySound('GAM_44') refreshMageBook()"
}
list
{
column
{
width 100
label
{
area 0 0 -1 -1
bam lua "bottomSpells[rowNumber].icon"
align center center
greyscale lua "bottomSpells[rowNumber].castable == 0"
}
}
area 72 658 718 36
name "memorizedListMage"
enabled "#bottomSpells ~= 0 and isSpecialist(0)"
rowwidth 36
table "bottomSpells"
var currentBottomSpell
action
"
if bookMode == 0 then
showMageMemorizationFlash = false
mageScreen:UnmemorizeSpell( bottomSpells[currentBottomSpell].level, bottomSpells[currentBottomSpell].memorizedIndex )
Infinity_PlaySound('GAM_44')
elseif bookMode == 1 then
mageScreen:UnSequenceSpell( bottomSpells[currentBottomSpell].resref )
table.remove(sequencerSpells, currentBottomSpell)
bottomSpells = sequencerSpells
currentBottomSpell = 0
end
"
}
label
{
area 282 594 300 40
text lua "magePageInfo()"
text style "label"
rectangle 0
}
button
{
area 582 594 230 44
enabled "bookMode == 0 and (#characters[id].contingencySpells > 0 or #characters[id].sequencerSpells > 0)"
bam GUIBUTMT
text "CONTINGENCY_BUTTON"
text style "button"
action "Infinity_PushMenu('MAGE_CONTINGENCY')"
}
button
{
area 52 594 230 44
bam GUIBUTMT
enabled "bookMode == 1 or characters[id].hasMageBook"
clickable lua "(#bottomSpells < #bottomSpellsPlaceHolder or SpecialistMemorize()) and currentBookSpell ~= 0"
text "MEMORIZE_BUTTON"
text style "button"
action
"
if bookMode == 0 then
createMageMemorizationSparkle(1, 0, 40, 40, 'bookListMage', -1)
showMageMemorizationFlash = true
mageScreen:MemorizeSpell( characters[id].mageSpells[currentSpellLevel][currentBookSpell].level, characters[id].mageSpells[currentSpellLevel][currentBookSpell].index )
elseif bookMode == 1 then
mageScreen:SequenceSpell( bookSpells[currentBookSpell].resref )
end
"
}
button
{
area 582 594 230 44
enabled "bookMode == 1"
bam GUIBUTMT
text lua "contingencyDoneButtonText()"
text style "button"
action
"
if contingencyComplete() then
mageScreen:DoneSequencingSpells()
else
mageScreen:CancelSequencingSpells()
end
e:SelectEngine(worldScreen)
"
}
}
Note: The slot will be unusable if you have no spells of your spell school for a given spell level, and some schools have no spells at certain spell levels in the unmodded game.
Edit: Fixed game path.