Skip to content

Scrolls for sorcerers

2»

Comments

  • chimericchimeric Member Posts: 1,163

    Actually no, the classes and such are in the game - I would love it if the engine was more amenable to letting us apply house rules, to make more and more significant changes to classes. But alas, the engine is old and stuff and creaky.

    That doesn't impose any obligations on me, does it? I'm doing what I can to make playing magic-users (wizards, sorcerers...) more interesting, any way I can. It'll probably take more than a handful of new spells. It'll take a few handfuls. And how I wish I could make those spells do more, or that the engine was more amenable. Well, this is what it CAN do, at least. Preconceptions about good design, well-worn ideas about classes made distinct by their handicaps - those things I have no respect for, any more than if someone advised me to walk like everyone else - on a pair of crutches.

    Why not throw away the wizard and the sorcerer and make a new mage class? There are several reasons.

    1) Because I don't have the skills for such an overhaul.

    2) Because it would turn away players who like the wizard and the sorcerer much more than anything I might do with spells or scrolls, and I would lose 90% of audience - just another crazy self-serving mod.

    3) Because it would miss the point. It would fail to change what should be changed and discard what is to some extent valuable. The bookish wizard is not hopeless. And, grumble as I might about Personality magic, I understand that this idea too has a basis in the mythical reality, only it has found expression in D&D in an echoed, confused and weak form, and popular concepts about it go wide of the target. Talents don't preclude learning, not even from books, but there is a broader array of sources one could learn from to develop. I've mentioned a few possibilities already, but there is no way I could unfold them in these games even with a top-notch engine and advanced skills, and all the time in the world. I can only invite you to re-open a Fritz Leiber book or go through Howard's tales of Conan ("The Hour of the Dragon" is the most splendid example) to get a feeling for how rich, exciting and varied wizardry can be. Roger Zelazny's "Changeling" is a not-bad attempt at Personality magic - and, by the way, conveys a sense of how desperately impossible it would be to have something like that in an RPG. A real attempt at either would require entire game worlds, maybe even the whole D&D game to be reconceived before even setting down to code. It's beyond possible.

    Therefore, any class replacement I could try here, with these worlds and cogs we are given, would be a sham, a pretended novelty that would only redistribute power without looking at its origins, conditions or meaning. And there are already enough mods that do that (not to mention any names). The solution, then, is to do the opposite - refrain from sweeping but superficial changes (moth, stop beating on the lamp shade) and work more or less within the existing system, where it suits me, but offer options not explored before. All this, of course, is much easier to say than to impress players held fast by nostalgia and jaded after a slew of mods that only attempt to tweak the game this way or that. It has been tweaked so much, it's twitching. As you can see in this thread, it is very difficult to explain even the concept of a change that is not some kind of preference tweak. I've given up the explaining, it sounds like drawing on credit I won't be able to repay. I'm only telling you all this out of respect for yourself and because you've shown me the ropes of Weidu a while ago.

    4) The final reason is simply that, other things being equal, a new class isn't necessary for what I wish to do. I don't like the memorization system much, but neither does it bother me greatly; it adds a degree of depth, though not of the right kind. The sorcerer is overpowered only compared to the other classes, but you don't have to compare him to them. Play him as you wish, not as the imperfect mechanics tell you to. If you think that the sorcerer should not get his spells of choice for free, choose a second-rate spell sometimes and pretend to yourself this was all that was available. Don't turn him into a walking cannon and don't ask for "best spells for Sorcerer" on the board. I'm not saying that you do that yourself, but others - yes, they do it, and they cheat themselves as a result. In general, players of these games that I see here are far too out-of-character, too obsessed with winning - even though the 2nd Edition PHB states loud and clear in the very beginning that one doesn't "beat" a role-playing game. With that I agree entirely. And as modders we should instead strive to bring more fantasy, mystery, ideas, situations to the games, just plain fun - as much as we can. We owe nothing to bad mechanics, or to bad pen-and-paper design, or to bad assumptions in people's heads. It's in this sense that I say that classes and balance don't exist. They don't matter in themselves. They aren't bad - they aren't good - they are just like stones on the road. Kick them, admire them, build a house out of them, try not to trip over other people if you move them, anything you want - just don't set them up as idols to be attended, prayed to and polished.

    Also, the whole proposal stems from your desire to keep these spells out of the IDS table, which I confess I don't understand. I advised caution when dealing with IDS entries, but not abstinence. If there is a reason to add a new spell to the IDS table - and, wanting sorcerers to be able to cast it is a good reason - then you might as well add it.

    I think you must understand why by now. Because I don't want to make any changes that will achieve nothing really important but MAY get me bogged down in compatibility issues, systemic changes, Weidu coding and other profound-sounding matters that could very well be bad for the mod and would waste a lot of my time. I don't need most IDS files, only, perhaps, some IDS-changing code for projectiles and such; or perhaps I'll leave even that as a manual change. Edit a few files at install. Going deep is not always a good idea. Remember how I suggested that simply doing spell lists for the different priest Spheres, and inscribing them via triggers, would be the easiest way to give priest characters their due spell selection? It really would be. Straight into the book. I understand that plunging into the guts of the engine, finding smart solutions can become a pleasure in its own right: idea, error, correction, new idea, breakthrough, setback, discussing progress on the forums, getting praise and feedback that leads to another idea... It's a rush. And I'm very impressed that you can indeed figure out a way to bind the "iron" to your will. I wouldn't be able to do that in a million years - not that I would want to spend them that way. I think, however, that we should keep our discipline up and leave alone as much as we can: the engine, classes, existing spells... Just leave alone everything, even if it's imperfect, but what has to be changed to give players a new and fun experience, in the most direct way possible.

    And, as it happens, that means scrolls sorcerers could use. :smiley:
  • The user and all related content has been deleted.
  • gorgonzolagorgonzola Member Posts: 3,864
    On-topic, regarding sorcerers who can learn from scrolls some people may like it and other dislike it and imo every opinion is fine. But from the balance point of view there is a thing to tell.
    The fact that in vanilla they can learn only a certain number of spells is only one of the things that compensate their versatility in using the known spells in battle, the other is that they can not dual or multi class, and this alone helps in balancing them against the wizards.
  • chimericchimeric Member Posts: 1,163
    You all remind me of those people on a bus who complain to the driver when he drives them past the stop, and he says "There is that BUTTON over there! Push it if you want me to stop!" But the idea that whether they end up in the right place or in the wrong place is up to them is not something they can wrap their minds around. They don't see the bus for what it is, the driver for what he is, they have a glittering vision of proper transportation, and they will debate that ideal and protest to Transportation Authority sooner than learn to get up and walk off.

    Well, if my explanations go this wide of understanding, you won't see me doing any more.

    To @subtledoctor : I may underestimate many things when it comes to this engine, but adding spells directly IS easy. Here is what you do: make a talking item with several identical reply lines, all of which say "Pray for divine favor." Each one has a trigger in front: if priest character level equals 1, 3, 5 and so on - for every character level when a priest is supposed to obtain new spells. 7 priest spell levels, 7 reply lines. The reply lines THEN DO each fire a spell at the PC, and that spell contains Learn Spell effects for all of the newly accessed level's spells you want the priest to have. 7 levels of priest spells - 7 SPL files to make that will put the spells in his spell book.

    This is without Spheres. With Spheres, it gets a bit more complicated, because you would have to set a number of Globals, as many as there are Spheres open to the given priest kit, at the start of the game. Set Protection to 1, Healing to 1, Sun to 0 and so on, as fits the kit. The reply lines for the item would then have those Globals as extra triggers in front of them. The SPL would have appropriate spells, maybe no spells for an empty Sphere. You would, for example, put in the SPL triggered by a level 3, Sun-enabled reply line all spells that you feel should be spell level 3 and of the Sun Sphere. Each SPL would be like a pocket. And you could expand the contents, put more in the pockets, later - any time somebody invented new priest spells, or imported some from another IE game and so on. You would just add Learn Spell effects for them. No IDS struggle, no trade-offs, no existential angst.

    I'm not saying setting all this up wouldn't be very boring and time-consuming work, but it's completely straightforward. There are some minor issues I can think of, but they ARE minor, and could be countered or tolerated.
  • chimericchimeric Member Posts: 1,163
    edited August 2016
    Here is another idea for sorcerers. Not what I'm going to do, but it crossed my mind as an alternative to scroll learning. Maybe they could learn magic from being exposed to it? Experience it first-hand. This plays rather well to the tune of discovering your self through adventures, better than "These spells just pop in my mind." All it takes is putting an indirect Learn Spell effect inside a Fireball. You want to know how to throw fire? Get a feel for it! Since some spells only affect enemies, a determined sorcerer would have to practically seek those who can let him taste Confusion etc. Masochistic? Yes, but they are strange types, these natural romantics... Want to experience everything first-hand...

    My kind of magician.


    If you are curious where I am vis-a-vis scrolls in my mod, I should tell you that learning a spell turns out to come with a repeating XP reward. You don't see in a regular game, but a character can be made to learn a spell over and over again, and every time he gets the XP for it. And since I had to look for roundabout ways to scribe scrolls for sorcerers, through outside Learn Spell effects, this becomes an issue without a mess of fence Globals. So what I might do is forbid sorcerers to use the same scroll more than once - so basically just let them learn from the scrolls, and then they are on their own. Less bookish this way, too.
  • The user and all related content has been deleted.
  • kjeronkjeron Member Posts: 2,367
    Copy+Paste into text editor, SaveAs "Whatever.tp2"
    Grab copy of Weidu, rename "Setup-Whatever.exe"
    Run in game folder.
    Caveats:
    - Scrolls must be unstacked before learning spells(or the whole stack will be lost).
    - Mage's learn chance is obtained at installation, changes to INTMOD need to be done prior.
    - Maximum number of spells per spell level is lost, but spell levels will still have minimum INT requirements.
    - Specialists, and only specialists, get their +/-15% learn chance. Trueclass Mages, other mage kits, and Bards of any kind do not have any bonus/penalty.
    - Sorcerers have no learn chance, replacement is always successful.
    - Sorcerers may only replace a spell if a scroll exists to learn that spell - they cannot replace irreplaceable spells. Spells on the Hidespl list are also excluded.
    - v2.+ only.
    Code:
    BACKUP ~SCROLL_SCRIBEDIALOGUE~
    AUTHOR ~none~ 
    VERSION ~1.0~
    
    BEGIN ~Allow Sorcerer's to replace Known Spells through Scrolls~
    	CLEAR_ARRAYS
    	
    	OUTER_SET	learn = RESOLVE_STR_REF(~Learn~)
    	COPY_EXISTING	~HIDESPL.2da~	override
    		COUNT_2DA_COLS	col	COUNT_2DA_ROWS	col	num_rows	value = 0
    		FOR	(i = 0; i < num_rows; ++i)	BEGIN
    			READ_2DA_ENTRY	i 0 col	resource
    			READ_2DA_ENTRY	i 1 col	value
    			PATCH_IF	(value = 1)	BEGIN
    				INNER_ACTION	BEGIN
    					OUTER_SET	$ignore(~%resource%~) = 1
    				END
    			END
    		END
    	BUT_ONLY
    	
    	OUTER_SET	index = 0
    	OUTER_SET	splidx = 0
    	
    	COPY_EXISTING_REGEXP	~.*\.itm$~	override
    		READ_SHORT	0x1c	category
    		PATCH_IF	category = 11	BEGIN
    			READ_LONG 	0x64	ab_off
    			READ_SHORT	0x68	ab_num
    			READ_SHORT	0x6a	fx_off
    			FOR	(i = 0; i < ab_num; ++i)	BEGIN
    				READ_SHORT (ab_off + i * 0x38 + 0x1e) fx_num
    				READ_SHORT (ab_off + i * 0x38 + 0x20) fx_idx
    				FOR(j = 0; j < fx_num; ++j)	BEGIN
    					READ_SHORT (fx_off + (j + fx_idx) * 0x30) opcode
    					PATCH_IF	opcode = 147	BEGIN
    						READ_ASCII (fx_off + (j + fx_idx) * 0x30 + 0x14) resource	
    						TO_UPPER resource
    						READ_BYTE	0x19	flag
    						WRITE_BYTE	0x19	(flag BOR 8)
    						SET	j = fx_num	SET	i = ab_num
    						INNER_ACTION	BEGIN
    							ACTION_IF	!VARIABLE_IS_SET	$ignore(~%resource%~)	BEGIN
    								OUTER_SPRINT	$itm(~%index%~)	~%SOURCE_RES%~
    								OUTER_SPRINT	$res(~%index%~)	~%resource%~
    								OUTER_SET	index += 1
    								ACTION_IF	!VARIABLE_IS_SET	$spl(~%resource%~)	BEGIN
    									OUTER_SPRINT	$spl(~%splidx%~) ~%resource%~
    									OUTER_SET	$spl(~%resource%~) = 1
    									OUTER_SET	splidx += 1
    								END
    							END
    						END
    					END
    				END
    			END
    		END
    	BUT_ONLY
    	
    	OUTER_FOR	(i = 1; i < 10; ++i)	BEGIN
    		OUTER_SPRINT	EVAL ~scrolldlg_%i%~
    ~~~~~BEGIN ~itemres~
    IF	~Class(Myself,SORCERER)~	THEN	BEGIN	0
    	SAY	~Which spell will you replace?~
    ~~~~~
    	END
    	
    	OUTER_FOR	(i = 0; i < splidx; ++i)	BEGIN
    		OUTER_SPRINT	file	EVAL $spl(~%i%~)
    		COPY_EXISTING_REGEXP	~%file%.spl~	override
    			READ_LONG	NAME1	name
    			READ_LONG	0x34	level
    			READ_BYTE	0x25	school	PATCH_IF	school > 8 BEGIN	school = 0	END
    			TO_UPPER SOURCE_RES
    			INNER_ACTION	BEGIN
    				OUTER_SET	$lvl(~%SOURCE_RES%~) = level
    				OUTER_SET	$sch(~%SOURCE_RES%~) = school
    				CREATE	SPL	VERSION ~V1  ~	~d%SOURCE_RES%~
    					INSERT_BYTES (0x72) 0x28
    						WRITE_BYTE (0x72 + 0x0)	1	WRITE_BYTE	(0x72 + 0x2)	4	WRITE_BYTE	(0x72 + 0xc)	5
    						WRITE_SHORT	(0x72 + 0x10)	1	WRITE_SHORT 0x68 1	WRITE_LONG	0x6a (0x72 + 0x28)
    					LPF	ADD_SPELL_EFFECT	INT_VAR	opcode = 172	target = 1	STR_VAR	resource = EVAL ~%SOURCE_RES%~	END
    				OUTER_SPRINT	EVAL ~scrolldlg_%level%~	EVAL ~~~~~%scrolldlg_%level%%
    IF ~HaveKnownSpellRES("%SOURCE_RES%")~	THEN	REPLY	#%name%	DO	~AddSpecialAbility("resref")		ApplySpellRES("d%SOURCE_RES%",Myself)	DestroyItem("itemres")~	EXIT~~~~~
    			END
    		BUT_ONLY
    	END
    	
    	OUTER_FOR	(i = 1; i < 10; ++i)	BEGIN
    		OUTER_SPRINT	EVAL ~scrolldlg_%i%~	EVAL ~~~~~%scrolldlg_%i%%
    IF	~~	THEN	REPLY	~Cancel~	DO	~~	EXIT
    END~~~~~
    	END
    	
    	COPY_EXISTING	~INTMOD.2DA~	override
    		COUNT_2DA_COLS	cols
    		COUNT_2DA_ROWS	cols rows
    		FOR	(i = 0; i < rows; ++i)	BEGIN
    			READ_2DA_ENTRY	i 0 cols value
    			READ_2DA_ENTRY	i 1 cols chance
    			INNER_ACTION	BEGIN
    				OUTER_SET	$int(~%value%~) = chance
    			END
    		END
    	BUT_ONLY
    	
    	OUTER_FOR	(i = 0; i < index; ++i)	BEGIN
    		OUTER_SPRINT	itm EVAL $itm(~%i%~)
    		OUTER_SPRINT	res EVAL $res(~%i%~)
    		OUTER_SET	lvl = $lvl(~%res%~)
    		OUTER_SET	school = $sch(~%res%~)
    			ACTION_IF	school = 1	BEGIN	OUTER_SET	opp_1 = 2**(5 + 2)	OUTER_SET	opp_2 = 2**(5 + 3)	OUTER_SET	opp_3 = 2**(5 + 4)	OUTER_SET	opp_4 = 2**(5 + 5)	OUTER_SET	opp_5 = 2**(5 + 6)	OUTER_SET	opp_6 = 2**(5 + 7)	OUTER_SET	opp_7 = 2**(5 + 8)	END	//	Abjuration -> Transmutation
    			ACTION_IF	school = 2	BEGIN	OUTER_SET	opp_1 = 2**(5 + 1)	OUTER_SET	opp_2 = 2**(5 + 4)	OUTER_SET	opp_3 = 2**(5 + 5)	OUTER_SET	opp_4 = 2**(5 + 6)	OUTER_SET	opp_5 = 2**(5 + 7)	OUTER_SET	opp_6 = 2**(5 + 8)	OUTER_SET	opp_7 = 2**(5 + 3)	END	//	Conjuration -> Divination
    			ACTION_IF	school = 3	BEGIN	OUTER_SET	opp_1 = 2**(5 + 1)	OUTER_SET	opp_2 = 2**(5 + 4)	OUTER_SET	opp_3 = 2**(5 + 5)	OUTER_SET	opp_4 = 2**(5 + 6)	OUTER_SET	opp_5 = 2**(5 + 7)	OUTER_SET	opp_6 = 2**(5 + 8)	OUTER_SET	opp_7 = 2**(5 + 2)	END	//	Divination -> Conjuration
    			ACTION_IF	school = 4	BEGIN	OUTER_SET	opp_1 = 2**(5 + 1)	OUTER_SET	opp_2 = 2**(5 + 2)	OUTER_SET	opp_3 = 2**(5 + 3)	OUTER_SET	opp_4 = 2**(5 + 5)	OUTER_SET	opp_5 = 2**(5 + 7)	OUTER_SET	opp_6 = 2**(5 + 8)	OUTER_SET	opp_7 = 2**(5 + 6)	END	//	Enchantment -> Evocation
    			ACTION_IF	school = 5	BEGIN	OUTER_SET	opp_1 = 2**(5 + 1)	OUTER_SET	opp_2 = 2**(5 + 2)	OUTER_SET	opp_3 = 2**(5 + 3)	OUTER_SET	opp_4 = 2**(5 + 4)	OUTER_SET	opp_5 = 2**(5 + 6)	OUTER_SET	opp_6 = 2**(5 + 8)	OUTER_SET	opp_7 = 2**(5 + 7)	END	//	Illusion -> Necromancy
    			ACTION_IF	school = 6	BEGIN	OUTER_SET	opp_1 = 2**(5 + 1)	OUTER_SET	opp_2 = 2**(5 + 2)	OUTER_SET	opp_3 = 2**(5 + 3)	OUTER_SET	opp_4 = 2**(5 + 5)	OUTER_SET	opp_5 = 2**(5 + 7)	OUTER_SET	opp_6 = 2**(5 + 8)	OUTER_SET	opp_7 = 2**(5 + 4)	END	//	Evocation -> Enchantment
    			ACTION_IF	school = 7	BEGIN	OUTER_SET	opp_1 = 2**(5 + 1)	OUTER_SET	opp_2 = 2**(5 + 2)	OUTER_SET	opp_3 = 2**(5 + 3)	OUTER_SET	opp_4 = 2**(5 + 4)	OUTER_SET	opp_5 = 2**(5 + 6)	OUTER_SET	opp_6 = 2**(5 + 8)	OUTER_SET	opp_7 = 2**(5 + 5)	END	//	Necromancy -> Illusion
    			ACTION_IF	school = 8	BEGIN	OUTER_SET	opp_1 = 2**(5 + 2)	OUTER_SET	opp_2 = 2**(5 + 3)	OUTER_SET	opp_3 = 2**(5 + 4)	OUTER_SET	opp_4 = 2**(5 + 5)	OUTER_SET	opp_5 = 2**(5 + 6)	OUTER_SET	opp_6 = 2**(5 + 7)	OUTER_SET	opp_7 = 2**(5 + 1)	END	//	Transmutation -> Abjuration
    		OUTER_SET	school = 2**(school + 5)
    		OUTER_SET	min = lvl * 2	ACTION_IF	min < 9 BEGIN	OUTER_SET	min = 9	END
    		OUTER_SET	state = 1
    		OUTER_SPRINT	patchdlg EVAL ~%scrolldlg_%lvl%%~
    		OUTER_FOR	(j = min; j < 26; ++j)	BEGIN
    			OUTER_SET	ltchnc = 100 - $int(~%j%~)	ACTION_IF	ltchnc < 0 BEGIN	OUTER_SET	ltchnc = 0	END
    			OUTER_SET	gtchnc = ltchnc - 1					ACTION_IF	gtchnc < 0 BEGIN	OUTER_SET	gtchnc = 0	END
    			OUTER_SET	sltchnc = ltchnc - 15				ACTION_IF	sltchnc < 0 BEGIN	OUTER_SET	sltchnc = 0	END
    			OUTER_SET	sgtchnc = gtchnc - 15				ACTION_IF	sgtchnc < 0 BEGIN	OUTER_SET	sgtchnc = 0	END
    			OUTER_SET	oltchnc = gtchnc + 15				ACTION_IF	oltchnc < 0 BEGIN	OUTER_SET	oltchnc = 0	END
    			OUTER_SET	ogtchnc = ltchnc + 15				ACTION_IF	ogtchnc < 0 BEGIN	OUTER_SET	ogtchnc = 0	END
    			ACTION_IF	school > 32	BEGIN
    				OUTER_SPRINT	patchdlg EVAL ~~~~~%patchdlg%
    IF	~!Class(Myself,SORCERER)	Class(Myself,MAGE_ALL) CheckStat(Myself,%j%,38)	Kit(Myself,%school%)	!HaveKnownSpellRES("resref")~	THEN	BEGIN	%state%
    SAY	~Scribe Scroll?~
    IF	~RandomNumGT(100,%sgtchnc%)~	THEN	REPLY	~Yes~	DO	~AddSpecialAbility("resref")	DestroyItem("itemres")~	EXIT
    IF	~RandomNumLT(100,%sltchnc%)~	THEN	REPLY	~Yes~	DO	~DisplayString(Myself,10831)	DestroyItem("itemres")~	EXIT
    IF	~~	THEN	REPLY	~No~	DO	~~	EXIT
    END~~~~~
    				OUTER_SET	state += 1
    				OUTER_SPRINT	patchdlg EVAL ~~~~~%patchdlg%
    IF	~!Class(Myself,SORCERER)	Class(Myself,MAGE_ALL) CheckStat(Myself,%j%,38)	OR(6)	Kit(Myself,%opp_1%)	Kit(Myself,%opp_2%)
    	Kit(Myself,%opp_3%)	Kit(Myself,%opp_4%)	Kit(Myself,%opp_5%)	Kit(Myself,%opp_6%)	!HaveKnownSpellRES("resref")~	THEN	BEGIN	%state%
    SAY	~Scribe Scroll?~
    IF	~RandomNumGT(100,%ogtchnc%)~	THEN	REPLY	~Yes~	DO	~AddSpecialAbility("resref")	DestroyItem("itemres")~	EXIT
    IF	~RandomNumLT(100,%oltchnc%)~	THEN	REPLY	~Yes~	DO	~DisplayString(Myself,10831)	DestroyItem("itemres")~	EXIT
    IF	~~	THEN	REPLY	~No~	DO	~~	EXIT
    END~~~~~
    				OUTER_SET	state += 1
    				OUTER_SPRINT	patchdlg EVAL ~~~~~%patchdlg%
    IF	~!Class(Myself,SORCERER)	Class(Myself,MAGE_ALL) CheckStat(Myself,%j%,38)	!Kit(Myself,%school%)	!Kit(Myself,%opp_1%)	!Kit(Myself,%opp_2%)
    	!Kit(Myself,%opp_3%)	!Kit(Myself,%opp_4%)	!Kit(Myself,%opp_5%)	!Kit(Myself,%opp_6%)	!Kit(Myself,%opp_7%)	!HaveKnownSpellRES("resref")~	THEN	BEGIN	%state%
    SAY	~Scribe Scroll?~
    IF	~RandomNumGT(100,%gtchnc%)~	THEN	REPLY	~Yes~	DO	~AddSpecialAbility("resref")	DestroyItem("itemres")~	EXIT
    IF	~RandomNumLT(100,%ltchnc%)~	THEN	REPLY	~Yes~	DO	~DisplayString(Myself,10831)	DestroyItem("itemres")~	EXIT
    IF	~~	THEN	REPLY	~No~	DO	~~	EXIT
    END~~~~~
    				OUTER_SET	state += 1
    			END	ELSE	BEGIN
    				OUTER_SPRINT	patchdlg EVAL ~~~~~%patchdlg%
    IF	~!Class(Myself,SORCERER)	Class(Myself,MAGE_ALL) CheckStat(Myself,%j%,38)	!HaveKnownSpellRES("resref")~	THEN	BEGIN	%state%
    SAY	~Scribe Scroll?~
    IF	~RandomNumGT(100,%gtchnc%)~	THEN	REPLY	~Yes~	DO	~AddSpecialAbility("resref")	DestroyItem("itemres")~	EXIT
    IF	~RandomNumLT(100,%ltchnc%)~	THEN	REPLY	~Yes~	DO	~DisplayString(Myself,10831)	DestroyItem("itemres")~	EXIT
    IF	~~	THEN	REPLY	~No~	DO	~~	EXIT
    END~~~~~
    				OUTER_SET	state += 1
    			END
    			OUTER_SPRINT	patchdlg EVAL ~~~~~%patchdlg%
    IF	~Class(Myself,BARD_ALL) CheckStat(Myself,%j%,38)	!HaveKnownSpellRES("resref")~	THEN	BEGIN	%state%
    SAY	~Scribe Scroll?~
    IF	~RandomNumGT(100,%gtchnc%)~	THEN	REPLY	~Yes~	DO	~AddSpecialAbility("resref")	DestroyItem("itemres")~	EXIT
    IF	~RandomNumLT(100,%ltchnc%)~	THEN	REPLY	~Yes~	DO	~DisplayString(Myself,10831)	DestroyItem("itemres")~	EXIT
    IF	~~	THEN	REPLY	~No~	DO	~~	EXIT
    END~~~~~
    			OUTER_SET	state += 1
    		END
    		OUTER_PATCH_SAVE	tempdlg ~%patchdlg%~	BEGIN
    			REPLACE_TEXTUALLY	~resref~	~%res%~
    			REPLACE_TEXTUALLY	~itemres~	~%itm%~
    		END
    		<<<<<<<< ...%itm%.d
    %tempdlg%
    >>>>>>>>
    		COMPILE	EVAL ~...%itm%.d~
    		APPEND	~ITEMDIAL.2DA~	~%itm%        %learn%  %itm%~
    	END
    CLEAR_ARRAYS

    Sample:

    Mage/Bard

    Sorcerer

  • chimericchimeric Member Posts: 1,163
    edited September 2016

    2) Yes, adding spells is trivially easy (and in fact your idea of using an item and a script is needlessly complex). Taking spells away from priests is quite another matter. Because adding them doesn't mean anything unless you first take them away. But then, you need to get through character generation. So you can't take them all away. And of course there is the Shaman kit, which will be broken by all of those manipulations. And then there are mod kits - anyone using my mod is (almost by definition) likely to use other mods as well, so we don't want my mod to break other is kits. And then there are mod spells. And differences between spells, and between versions of the same spell, across different games....

    Etc. etc. etc.

    Leave the All sphere enabled for the picks in the character generation. All priests have access to the All sphere. The Shaman (which is crap) may be compromised, and should probably not be a sub-type of cleric at all, compatibility with all other mods you can't guarantee, and there is no reason to, or even with the largest possible number of mods. I say above that I want my mod to be as broadly compatible as possible, the IDS thing is to get around one obvious limitation, but not at the expense of fun. The complex changes in mechanics you are laboring so hard at will involve you in even more changes, provisos and conditions; because it's an overhaul, but a simple add-on like what I suggest, or like my spell mod. You want to go deep, well, you'll end up pulling some roots. Why not let people pick and choose mods, admit that many kits won't be compatible, and uninstall them when they want something else?

    So suppose that the Shaman gets hopelessly disrupted if you take all spells away. Well, so what? The player who installed the mod that did this obviously wasn't interested in the Shaman for this playthrough, if he read the warning. So let him enjoy the clerics with their sphere selection or a druid. Many other character classes will be left untouched for him to take up, if he wants to play a couple of characters at once. Not everybody, but - tough nuggies. Nobody can expect people to invest thousands of man-hours into covering every base. When he is done with the priest, let him uninstall the spheres mod and play the Shaman then, or something else. But you want Utopia - a glory land where everyone will get along at the price of some serious implied handicaps on what may and may not be done in a mod and how. Remember the prefixes argument? A perfect snapshot. Compatibility, your way, means deciding on a system everyone will use, and then playing by those rules, whether people like them or not. Stray at your own risk; no scrolls for sorcerers without making a whole new class! You don't want to take risks, and you won't allow others. Because if people knew when they could walk off the bus, your complicated bells and whistles would be obsolete.

    1)You are at the beginning of a path 10 miles long, and only the first 10 yards are clearly visible. You see some "minor issues" in those first 10 yards and say "only a few minor issues! Clearly the rest of the path will be smooth sailing, because I don't perceive any issues except for these ones!"

    On that 10-mile road, there is a hill in the beginning, an outlook point not everyone can climb to, but sometimes even newbies can. And from that hill they see that all of the really interesting stuff on that road is somewhere around mile 3, or off the road on little paths. The next 7 miles are for runaway steam-rollers and people who drive them or run in front of them.
  • chimericchimeric Member Posts: 1,163
    kjeron said:

    Class

    Well, it's a possibility. I don't see a reason to bother limiting sorcerers to their number of spells through mechanics - I'm not afraid of myself - but why not. Only it adds text where text makes no meaningful impact, this copying should be done directly if possible... I guess it's not.
  • The user and all related content has been deleted.
  • chimericchimeric Member Posts: 1,163
    edited September 2016
    @kjeron , can you change that code so that the button automatically attempts a scribing for wizards and bards but shows this replacement dialogue for sorcerers? If it's so important to people that sorcerers don't get a broader variety of spells, if they actually enjoy being different by a handicap, why not let them. I can use this code for my scrolls... just a bit less text would be nice. Naturally, I'll mention your solution in the thanks.
  • The user and all related content has been deleted.
  • kjeronkjeron Member Posts: 2,367
    chimeric said:

    @kjeron , can you change that code so that the button automatically attempts a scribing for wizards and bards but shows this replacement dialogue for sorcerers? If it's so important to people that sorcerers don't get a broader variety of spells, if they actually enjoy being different by a handicap, why not let them. I can use this code for my scrolls... just a bit less text would be nice. Naturally, I'll mention your solution in the thanks.

    Dialogue cannot automatically execute actions, it requires player interaction, I think I could change it to not permit a Yes/No choice, but you would still have to press the "End Dialogue" button.
    I would have prefered to no even altered it for wizard/bards, except the 2 buttons use the same slot(dialogue/scribe) in the item description, and dialogue overrides scribe.
  • AquadrizztAquadrizzt Member Posts: 1,065
    Its interesting to see your way of approaching this @kjeron, the Arcanist kit I'm releasing in the next update of Tome and Blood actually does something very similar, but doesn't touch the scrolls themselves; it handles everything through a special ability.

    That way you can leave the scribe functionality intact.
  • kjeronkjeron Member Posts: 2,367
    edited September 2016
    This is probably as much as I can reduce it.
    A mage clicking the Learn button will be presented with one of the following Dialogues:
    Success, Fail, or Already Known, as appropriate.
    with no reply options, just the END DIALOGUE button.
    Also did some code cleanup, installs a lot faster now, and reads specialist school oppositions instead of assuming vanilla ones.
    [spoiler]
    BACKUP ~SCROLL_SCRIBEDIALOGUE~
    AUTHOR ~none~
    VERSION ~1.0~
    
    BEGIN ~Allow Sorcerer's to replace Known Spells through Scrolls~
    	OUTER_SET	learn = RESOLVE_STR_REF(~Learn~)
    	OUTER_SET	replace = RESOLVE_STR_REF(~Which spell will you replace?~)
    	OUTER_SET	cancel = RESOLVE_STR_REF(~Cancel~)
    	OUTER_SET	scribe = RESOLVE_STR_REF(~You copy the spell to you spellbook.~)
    	OUTER_SET	fail = RESOLVE_STR_REF(~You failed to copy the spell to your spellbook.~)
    	OUTER_SET	known = RESOLVE_STR_REF(~You already have this spell in your spellbook.~)
    	
    	COPY_EXISTING	~HIDESPL.2da~	override
    		COUNT_2DA_COLS	col	COUNT_2DA_ROWS	col	num_rows	value = 0
    		FOR	(i = 0; i < num_rows; ++i)	BEGIN
    			READ_2DA_ENTRY	i 0 col	resource
    			READ_2DA_ENTRY	i 1 col	value
    			PATCH_IF	(value = 1)	BEGIN
    				INNER_ACTION	BEGIN
    					OUTER_SET	$ignore(~%resource%~) = 1
    				END
    			END
    		END
    	BUT_ONLY
    	
    	OUTER_SET	index = 0
    	OUTER_SET	splidx = 0
    	
    	COPY_EXISTING_REGEXP	~.*\.itm$~	override
    		READ_SHORT	0x1c	category
    		PATCH_IF	category = 11	BEGIN
    			READ_LONG 	0x64	ab_off
    			READ_SHORT	0x68	ab_num
    			READ_SHORT	0x6a	fx_off
    			FOR	(i = 0; i < ab_num; ++i)	BEGIN
    				READ_SHORT (ab_off + i * 0x38 + 0x1e) fx_num
    				READ_SHORT (ab_off + i * 0x38 + 0x20) fx_idx
    				FOR(j = 0; j < fx_num; ++j)	BEGIN
    					READ_SHORT (fx_off + (j + fx_idx) * 0x30) opcode
    					PATCH_IF	opcode = 147	BEGIN
    						READ_ASCII (fx_off + (j + fx_idx) * 0x30 + 0x14) resource	
    						TO_UPPER resource
    						READ_BYTE	0x19	flag
    						WRITE_BYTE	0x19	(flag BOR 8)
    						SET	j = fx_num	SET	i = ab_num
    						INNER_ACTION	BEGIN
    							ACTION_IF	!VARIABLE_IS_SET	$ignore(~%resource%~)	BEGIN
    								OUTER_SPRINT	$itm(~%index%~)	~%SOURCE_RES%~
    								OUTER_SPRINT	$res(~%index%~)	~%resource%~
    								OUTER_SET	index += 1
    								ACTION_IF	!VARIABLE_IS_SET	$spl(~%resource%~)	BEGIN
    									OUTER_SPRINT	$spl(~%splidx%~) ~%resource%~
    									OUTER_SET	$spl(~%resource%~) = 1
    									OUTER_SET	splidx += 1
    								END
    							END
    						END
    					END
    				END
    			END
    		END
    	BUT_ONLY
    	
    	OUTER_FOR	(i = 1; i < 10; ++i)	BEGIN
    		OUTER_SPRINT	EVAL ~startdlg_%i%~
    ~~~~~BEGIN ~itemres~
    IF	~Class(Myself,SORCERER)	~~~~~	
    		OUTER_SPRINT	EVAL ~knowndlg_%i%~	~~
    	END
    	
    	COPY_EXISTING_REGEXP	~.*\.spl~	override
    		TO_UPPER SOURCE_RES
    		PATCH_IF	VARIABLE_IS_SET	$spl(~%SOURCE_RES%~)	BEGIN
    			READ_LONG	NAME1	name
    			READ_LONG	0x34	level
    			READ_BYTE	0x25	school	PATCH_IF	school > 8 BEGIN	school = 0	END
    			READ_SHORT	0x1e	exclude
    			TO_UPPER SOURCE_RES
    			INNER_ACTION	BEGIN
    				OUTER_SET	exidx = 0
    				OUTER_SET	opidx = 0
    				OUTER_FOR	(j = 6; j < 14; ++j)	BEGIN
    					ACTION_IF	(exclude BAND (2**j)) BEGIN
    						OUTER_SET	sch = (2**j)
    						OUTER_SET $exc(~%SOURCE_RES%~ ~%sch%~)	= 1
    					END
    				END
    				OUTER_SET	$lvl(~%SOURCE_RES%~) = level
    				OUTER_SET	$sch(~%SOURCE_RES%~) = school
    				CREATE	SPL	VERSION ~V1  ~	~d%SOURCE_RES%~
    					INSERT_BYTES (0x72) 0x28
    						WRITE_BYTE (0x72 + 0x0)	1	WRITE_BYTE	(0x72 + 0x2)	4	WRITE_BYTE	(0x72 + 0xc)	5
    						WRITE_SHORT	(0x72 + 0x10)	1	WRITE_SHORT 0x68 1	WRITE_LONG	0x6a (0x72 + 0x28)
    					LPF	ADD_SPELL_EFFECT	INT_VAR	opcode = 172	target = 1	STR_VAR	resource = EVAL ~%SOURCE_RES%~	END
    				OUTER_SPRINT	EVAL ~knowndlg_%level%~	EVAL ~~~~~%knowndlg_%level%%
    IF ~HaveKnownSpellRES("%SOURCE_RES%")~	THEN	REPLY	#%name%	DO	~AddSpecialAbility("resref")		ApplySpellRES("d%SOURCE_RES%",Myself)	DestroyItem("itemres")~	EXIT~~~~~
    			END
    		END
    	BUT_ONLY
    	
    	OUTER_FOR	(i = 1; i < 10; ++i)	BEGIN
    		OUTER_SPRINT	EVAL ~knowndlg_%i%~	EVAL ~~~~~%knowndlg_%i%%
    IF	~~	THEN	REPLY	#%cancel%	EXIT
    END~~~~~
    	END
    	
    	COPY_EXISTING	~INTMOD.2DA~	override
    		COUNT_2DA_COLS	cols
    		COUNT_2DA_ROWS	cols rows
    		FOR	(i = 0; i < rows; ++i)	BEGIN
    			READ_2DA_ENTRY	i 0 cols value
    			READ_2DA_ENTRY	i 1 cols chance
    			INNER_ACTION	BEGIN
    				OUTER_SET	$int(~%value%~) = chance
    			END
    		END
    	BUT_ONLY
    	
    	OUTER_FOR	(i = 0; i < index; ++i)	BEGIN
    		OUTER_SET	kits = 0	OUTER_SPRINT kitlist ~~	OUTER_SET	state = 1
    		OUTER_SPRINT	itm EVAL $itm(~%i%~)
    		OUTER_SPRINT	res EVAL $res(~%i%~)
    		OUTER_SET	lvl = $lvl(~%res%~)
    		OUTER_SPRINT	patchdlg EVAL ~~~~~%startdlg_%lvl%%	!HaveKnownSpellRES("resref")~	THEN	BEGIN	0
    	SAY	#%replace%	%knowndlg_%lvl%%~~~~~
    		OUTER_SET	min = lvl * 2	ACTION_IF	min < 9 BEGIN	OUTER_SET	min = 9	END
    		OUTER_SET	school = (2**($sch(~%res%~) + 5))
    		OUTER_FOR	(k = 6; k < 14; ++k)	BEGIN
    			OUTER_SET	kit = (2**k)
    			ACTION_IF	((school != kit) AND (!VARIABLE_IS_SET	$exc(~%res%~ ~%kit%~)))	BEGIN
    				OUTER_SPRINT	kitlist EVAL ~~~~~%kitlist%	Kit(Myself,%kit%)~~~~~
    				OUTER_SET	kits += 1
    			END
    		END
    		OUTER_FOR	(j = min; j < 26; ++j)	BEGIN
    			OUTER_SET	ltchnc = 101 - $int(~%j%~)	ACTION_IF	ltchnc < 0 BEGIN	OUTER_SET	ltchnc = 0	END
    			OUTER_SET	gtchnc = ltchnc - 1					ACTION_IF	gtchnc < 0 BEGIN	OUTER_SET	gtchnc = 0	END
    			OUTER_SET	sltchnc = ltchnc - 15				ACTION_IF	sltchnc < 0 BEGIN	OUTER_SET	sltchnc = 0	END
    			OUTER_SET	sgtchnc = gtchnc - 15				ACTION_IF	sgtchnc < 0 BEGIN	OUTER_SET	sgtchnc = 0	END
    			OUTER_SET	oltchnc = ltchnc + 15				ACTION_IF	oltchnc < 0 BEGIN	OUTER_SET	oltchnc = 0	END
    			OUTER_SET	ogtchnc = gtchnc + 15				ACTION_IF	ogtchnc < 0 BEGIN	OUTER_SET	ogtchnc = 0	END
    			ACTION_IF	school > 32	BEGIN
    				OUTER_SPRINT	patchdlg EVAL ~~~~~%patchdlg%
    					IF	~RandomNumGT(100,%sgtchnc%)		Class(Myself,MAGE_ALL) CheckStat(Myself,%j%,38)	Kit(Myself,%school%)	!HaveKnownSpellRES("resref")~
    					THEN	BEGIN	%state%	SAY	#%scribe%	IF ~~	DO	~AddSpecialAbility("resref")	DestroyItem("itemres")~	EXIT	END~~~~~
    				OUTER_SET	state += 1
    				OUTER_SPRINT	patchdlg EVAL ~~~~~%patchdlg%
    					IF	~RandomNumLT(100,%sltchnc%)		Class(Myself,MAGE_ALL) CheckStat(Myself,%j%,38)	Kit(Myself,%school%)	!HaveKnownSpellRES("resref")~
    					THEN	BEGIN	%state%	SAY	#%fail%	IF ~~	DO	~DestroyItem("itemres")~	EXIT	END~~~~~
    				OUTER_SET	state += 1
    				ACTION_IF	kits	BEGIN
    					OUTER_SPRINT	patchdlg EVAL ~~~~~%patchdlg%
    						IF	~RandomNumGT(100,%ogtchnc%)		Class(Myself,MAGE_ALL) CheckStat(Myself,%j%,38)	OR(%kits%)%kitlist%	!HaveKnownSpellRES("resref")~
    						THEN	BEGIN	%state%	SAY	#%scribe%	IF ~~	DO	~AddSpecialAbility("resref")	DestroyItem("itemres")~	EXIT	END~~~~~
    					OUTER_SET	state += 1
    					OUTER_SPRINT	patchdlg EVAL ~~~~~%patchdlg%
    						IF	~RandomNumLT(100,%oltchnc%)		Class(Myself,MAGE_ALL) CheckStat(Myself,%j%,38)	OR(%kits%)%kitlist%	!HaveKnownSpellRES("resref")~
    						THEN	BEGIN	%state%	SAY	#%fail%	IF ~~	DO	~DestroyItem("itemres")~	EXIT	END~~~~~
    					OUTER_SET	state += 1
    				END
    				OUTER_SPRINT	patchdlg EVAL ~~~~~%patchdlg%
    					IF	~RandomNumGT(100,%gtchnc%)		Class(Myself,MAGE_ALL) CheckStat(Myself,%j%,38)	!Kit(Myself,64)	!Kit(Myself,128)	!Kit(Myself,256)
    							!Kit(Myself,512)	!Kit(Myself,1024)	!Kit(Myself,2048)	!Kit(Myself,4096)	!Kit(Myself,8192)	!HaveKnownSpellRES("resref")~
    					THEN	BEGIN	%state%	SAY	#%scribe%	IF ~~	DO	~AddSpecialAbility("resref")	DestroyItem("itemres")~	EXIT	END~~~~~
    				OUTER_SET	state += 1
    				OUTER_SPRINT	patchdlg EVAL ~~~~~%patchdlg%
    					IF	~RandomNumLT(100,%ltchnc%)		Class(Myself,MAGE_ALL) CheckStat(Myself,%j%,38)	!Kit(Myself,64)	!Kit(Myself,128)	!Kit(Myself,256)
    							!Kit(Myself,512)	!Kit(Myself,1024)	!Kit(Myself,2048)	!Kit(Myself,4096)	!Kit(Myself,8192)	!HaveKnownSpellRES("resref")~
    					THEN	BEGIN	%state%	SAY	#%fail%	IF ~~	DO	~DestroyItem("itemres")~	EXIT	END~~~~~
    				OUTER_SET	state += 1
    			END	ELSE	BEGIN
    				OUTER_SPRINT	patchdlg EVAL ~~~~~%patchdlg%
    					IF	~RandomNumGT(100,%gtchnc%)		Class(Myself,MAGE_ALL) CheckStat(Myself,%j%,38)	!HaveKnownSpellRES("resref")~
    					THEN	BEGIN	%state%	SAY	#%scribe%	IF ~~	DO	~AddSpecialAbility("resref")	DestroyItem("itemres")~	EXIT	END~~~~~
    				OUTER_SET	state += 1
    				OUTER_SPRINT	patchdlg EVAL ~~~~~%patchdlg%
    					IF	~RandomNumLT(100,%ltchnc%)		Class(Myself,MAGE_ALL) CheckStat(Myself,%j%,38)	!HaveKnownSpellRES("resref")~
    					THEN	BEGIN	%state%	SAY	#%fail%	IF ~~	DO	~DestroyItem("itemres")~	EXIT	END~~~~~
    				OUTER_SET	state += 1
    			END
    			OUTER_SPRINT	patchdlg EVAL ~~~~~%patchdlg%
    				IF	~RandomNumGT(100,%gtchnc%)	Class(Myself,BARD_ALL) CheckStat(Myself,%j%,38)	!HaveKnownSpellRES("resref")~
    				THEN	BEGIN	%state%	SAY	#%scribe%	IF ~~	DO	~AddSpecialAbility("resref")	DestroyItem("itemres")~	EXIT	END~~~~~
    			OUTER_SET	state += 1
    			OUTER_SPRINT	patchdlg EVAL ~~~~~%patchdlg%
    				IF	~RandomNumLT(100,%ltchnc%)	Class(Myself,BARD_ALL) CheckStat(Myself,%j%,38)	!HaveKnownSpellRES("resref")~
    				THEN	BEGIN	%state%	SAY	#%fail%	IF ~~	DO	~DestroyItem("itemres")~	EXIT	END~~~~~
    			OUTER_SET	state += 1
    		END
    		OUTER_SPRINT	patchdlg EVAL ~~~~~%patchdlg%
    			IF	~HaveKnownSpellRES("resref")~	THEN	BEGIN	%state%	SAY	#%known%	IF ~~	EXIT	END~~~~~
    		OUTER_SET	state += 1
    		OUTER_PATCH_SAVE	tempdlg ~%patchdlg%~	BEGIN
    			REPLACE_TEXTUALLY	~resref~	~%res%~
    			REPLACE_TEXTUALLY	~itemres~	~%itm%~
    		END
    		<<<<<<<< ...%itm%.d
    %tempdlg%
    >>>>>>>>
    		COMPILE	EVAL ~...%itm%.d~
    		APPEND	~ITEMDIAL.2DA~	~%itm%        %learn%  %itm%~
    	END
    [/spoiler]
    If you replace the one instance of:
    Class(Myself,SORCERER)
    with
    Class(Myself,255)
    and remove all instances of:
    !Class(Myself,SORCERER)
    Sorcerer's will use the same learn chance as an unkitted mage.
    It will leave redundant code, but for a quick edit its easier to turn a false trigger than remove the code entirely without breaking something else.

    edit:- code typo
    Post edited by kjeron on
  • kjeronkjeron Member Posts: 2,367
    edited September 2016
    I found a way to revert Mages/Bards to the normal Write Magic function while using this, by modding the UI.
    It works, but looks ugly.
  • chimericchimeric Member Posts: 1,163
    Thanks, @kjeron . I decided against limiting sorcerers after all, but this may be useful code for someone else. I'll just put an extra effect in my scrolls, for sorcerers only, that summons an invisible creature who'll give them the learning XP and set a global for this never to happen again. So they'll have to cast the spell from the scroll to learn it. I might put a level check there too - no learning Time Stop in advance.
  • chimericchimeric Member Posts: 1,163
    I'm still thinking about this.

    Those of you who know about the Forgotten Realms a lot: in what congealed forms does magic exist there? Have you read about anything like that? Dust of magic, or possibly some kind of essence or mineral? Something from Mystra?
Sign In or Register to comment.