Let's assume you have already decided on a group (custom or otherwise)

Rules:
The discipline group: Quietus
The discpline we will be adding will be: Thin Blood
][ means we are done with that file.
Whitespacing (and kinds of whitespacing, tabs or spacebar) as well as capitalization is important.

First things first, I have to think of all the files I need to change to add a discipline.
We start at are usual starting point,
./misc/game.ndg - no changes there 
(we already have an entry for DGRP_Quietus, this walkthru aint about how to add new D.Groups!)
./misc/game.ncd - no changes there 

./misc/game.ndd - Yikes. Lets add an entry.


# QUIETUS               -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

ThinBlood               DGRP_Quietus                    thinBloodIcon           DisciplineThinBlood             disciplineCast_wobbleSputtr.WAV 0x28    10      0.0     200.0   0.0     2       250     15      15      15      10      10      2000    2000    2000    1000    1000    4   35  7   60  -   -


Spaceless name.

We will call the DGRP_* the DGRP label. Use the DGRP label.

Using custom made graphics. (ALL 3 icons have to be the right sizes and in ./ui/Icons)
NOTE: I have found that my targas dont have a specific alpha channel mask, but I did add 
the mask to Silence of Death. Adding it still doesnt help when transferring to the quick menu. 
Anyone know why the regular tga's turn into an oval and mine stay a rectangle? It has to do with
an extra 1000 bytes of info in the native targas...It's non-terminal, so we move on.

Since we will be creating this as a class, the script is the spaceless scriptname (ie classname)

Using premade sounds.

Next are the flags
# Flags:
#
# TARGET NONE	        0x01
# TARGET AREA	        0x02
# TARGET INVENTORY	0x04
# TARGET ENEMY		0x08
# TARGET FRIENDLY	0x10
# OFFENSIVE		0x20
# TARGET DEAD           0x40
# TARGET HEAD           0x80
It's OFFENSIVE && is used on TARGET ENEMY. That makes the composite flag, 0x28

Next column is TYPE
# Types:
#
# NONE	       	0       AI cannot use or use only in special conditions
# HEAL	       	1       Healing discipline	(when damaged)
# BUFF	       	2       Buffing discipline	(start of fight generally)
# SUMMON       	3       Summoning discipline    (start of fight generally)
# HIDE	       	4       Hide, sneak, etc.	(preferably at start of fight or when damaged too much)
# SENSE         5       Sense discipline        (used by AI on losing its target)
# FEED          6       Feed discipline
# RESERVED      7       (reserved, do not use)
# RESERVED      8       (reserved, do not use)
# RESERVED      9       (reserved, do not use)
# DAMAGE        10      Damage discipline	(in fight damage)
# MIND	       	11      Mind/control		(in fight mind control, fear, mesmerize, etc.)
# FRENZY        12      Makes frenzy higher
It's a hurtful discipline as far as the AI is concerned.
10

# minDist       minimum distance to cast (for AI)
# maxDist       maximum distance to cast (for AI)
I dont understand minDist/maxDist, probably for when the AI decides it's a good idea to cast it.
I copied acidic touch 
0.0 	200.0
- cast it when you are next to the enemy or no more than 200 paces away?

# fData         additional float data
I dunno. Probably for projectile physics, I'm copying acidic touch.
0.0

Cast Animation - an integer. I copied acidic touch.
2

# xpc           initial cost in experience to "buy" the discipline
for testing, this is 250

# cN            cost in blood to cast per level
15 down to 10 at later levels

# rN            time in ms before the discipline can be recast
copied acidic touch, 2000 then 1000 at later levels.

# csN           check stat
refers to stat by number, 7 is humanity. somebody MAKE A GODDAMN LIST

# cvN           check value
The character must have at least these values UNLESS the number is negative. 
-60 means the character must have 60 or lower in the csN attribute.

][


./misc/effect.ned
need an entry

ef_disc_thinblood               FXDeathIcon             1       EffectDiscThinBlood             36      6       5       0x0     500     0       0       3       6       9       12      15      18

If you read my hacking.txt the ef_disc_* should signal you that you are going to need to alter
the system.nls.
The Icon is actually either the icon that shows up in your hud. I'll find out where this icon
comes from later.
The next flag is what row the icon should show up in on your hud. I dont know how many rows there
are but acidic touch uses 1, so should I.
This is the name of the other class that we need to recompile, it will be a spaceless classname.
The next flag is part of where the engine will try to decide what it should actually DO now that
it knows what discipline you are going to use. I put in 36 which should error/crash the game if
I dont justify it somewhere else. In the header I put:
#  35   TEAMFRIENDLY    friendly to another team than his own (or more exactly, on top of his own)
#  36   *DISABILITY      generates a detrimental effect - User Defined [Jack9]
#
The * indicates there is a subtype. I put 6. My reasoning is that if the discipline ends up not
using a subtype, it *should* ignore the column completely. Other disciplines without subtypes
have 0 which represents Strength as a subtype, and seems to be ignored. Better safe than sorry.
The next flag is compose type. I think this means " it's placement in a stack of effects"
I dont know, so I call it 5 (ADD) because Acidic Touch does too.
Flag 0x0 since acidic touch does too.
Next, 500, same as A.T.
All the following flags...same as A.T. I dont know what changing them will do that will help/hurt
me. I'm worried about coding this stuff for reals, not tweaking numbers.

We know we have to mess with ./strings/system.nls so lets do it now.
I added the discipline label -> real Discipline name
and the disciplinelabel_L -> Discipline description when your pointer hovers over it.

// ............................................................................ 
// discipline names
// ............................................................................ 

// Quietus
THINBLOOD			Thin Blood

// Animalism
FERALWHISPERS                   Feral Whispers
BECKONING                       Beckoning
QUELLBEAST                      Quell The Beast

// ............................................................................ 
// long discipline names
// ............................................................................ 

// Quietus
THINBLOOD_L			Causes target to be unable to use bloodhealing powers.

// Animalism
FERALWHISPERS_L                 Enlists Targeted Animals to Your Aid
BECKONING_L                     Summons Animals to Your Aid
QUELLBEAST_L                    Lowers Frenzy Levels and Creates Complacency In Targeted Creatures

][

I guess we have to go do some java now. Unzip Codex.nob to your c:\jdk1.1.8\bin\
you better have unzipped jad here too
Open DOS window
cd c:\jdk1.1.8\bin\
jad Discipline.class
jad DisciplineAcidicTouch.class
jad EffectDiscAcidicTouch.class
rename *.jad *.java

Open c:\jdk1.1.8\bin from a new window and try to open the discipline.java
if the "what the fuck?" dialogue comes up, select notepad.
I ENCOURAGE THE USE OF NOTEPAD.EXE FOR ALL PROGRAMMING
It's the closest thing to vi/emacs :p
Out of the half-a-million-odd code that this game contains, you get to actually see some of it:

// Decompiled by Jad v1.5.7d. Copyright 2000 Pavel Kouznetsov.
// Jad home page: http://www.geocities.com/SiliconValley/Bridge/8617/jad.html
// Decompiler options: packimports(3) 
// Source File Name:   DisciplineAcidicTouch.java


public class DisciplineAcidicTouch extends Discipline
{

    public DisciplineAcidicTouch()
    {
    }

    public int cast(int level, int casterGuid, int targetGuid)
    {
        if(!CheckCastParameters(level, casterGuid, "AcidicTouch"))
            return 0;
        if(!CheckCastTarget(targetGuid, "AcidicTouch"))
            return 0;
        if(Fizzled(level))
        {
            DisplayFizzle("AcidicTouch", level);
            return 0;
        }
        try
        {
            targetThing.AddActorEffectByLevel("ef_disc_acidictouch", 2000, level, casterGuid, 4);
            DisplayCast("AcidicTouch", level);
            return 1;
        }
        catch(Exception e)
        {
            CodexConsole.PrintException(e.getMessage() + " in " + "AcidicTouch" + " [cast]");
            return 0;
        }
        catch(Error e)
        {
            CodexConsole.PrintError(e.getMessage() + " in " + "AcidicTouch" + " [cast]");
        }
        return 0;
    }

    private static final String DISCIPLINE_NAME = "AcidicTouch";
}

][
// My comments will be prefixed by these slashes in case you copy/paste [Jack9]
// This is also a beginning kind of programming tutorial.
// Rules: 
// If (blah blah blah) means 'If what is in my () is true, do the stuff in my {}'
// The computer thinks 1 means "true"
// The computer thinks 0 means "false"
// Ok, lets start hacking, all comments are thrown out by the compiler, so just remember to 
// change 1 line in the header for your own sanity.

// Source File Name:   DisciplineThinBlood.java

// We have to look at Discipline.class later, so far it looks fine, we WILL have a
// Discipline.class for it to inherit from when it compiles. But the name has to change.
// The name should match the script from the game.ndd entry

public class DisciplineThinBlood extends Discipline
{

// A function with the same name as the class is the constructor.
// You HAVE to have a constructor, even if it's empty.
// A constructor is usually used to do memory cleanup or initialization
// these are basic Java rules (and good practice in C)

    public DisciplineThinBlood()
    {
    }

// This is the most important method (or function). A function is called by something like this
// MyVariable = fooobject.cast(parameter, parameter)
// cast takes parameters...3 numbers it would seem. The caster (resolved to an ID number), the 
// target (same), and the level of the discipline (I think).

    public int cast(int level, int casterGuid, int targetGuid)
    {

// the following IF statement does not have {}! this is because ALL programmers are lazy.
// Usually us programmers only want 1 thing done if our IF statement works.
// So if there are no {}, the IF will only do the 1 line below it (it will be indented too).

// If (!true) is a tricky concept. This is a combination of function and operator.
// the function CheckCastParameters(level, casterGuid, "ThinBlood") is a function.
// just like almost every single function in the universe, it's going to 'return' a value.
// it will basically evaluate to a 1 or 0. The ! changes it to the opposite.
// If the CheckCastParameters returns a 1 the ! will change it to 0 and vice versa.
// This line checks to make sure the caster has the power. If he does the If() ends up with-
// If ( !1 ) , which evaluates to IF (0), 0 is false...and the function skips the next line 

        if(!CheckCastParameters(level, casterGuid, "ThinBlood"))
            return 0;

// The programmer could have wasted 2 more lines and 2 keystrokes to do this version, which 
//  works the exact same way.
//        if(!CheckCastParameters(level, casterGuid, "ThinBlood"))
//        {
//          return 0;
//        }

// By the way, return 0 means FAILURE, EXIT. We dont want this to fail.

// I dont know what this next line does, but it we will remember to look for the
// CheckCastTarget() function later...I just find-replace all the AcidicTouch strings with
// my ThinBlood one for now.

        if(!CheckCastTarget(targetGuid, "ThinBlood"))
            return 0;

// Ok, this is another IF(function()) {}
// Fizzled is a function that takes the level of the discipline and applies a random number
// to it. If it matches a preset value, or more, it works. Just remember, that all disciplines
// of the same level have the same chance of fizzling. The fizzle function doesnt care what kind
// of discipline you are using, it determines if it will fizzle or not based only on the level!

        if(Fizzled(level))
        {
// This prints "Thin Blood fizzled"...it gets 'Thin Blood' from ThinBlood by referencing the
// system.nls which we altered earlier.

            DisplayFizzle("AcidicTouch", level);
            return 0;
        }
// NOW that all that is done and it has decided it wants to work for us...
        try
        {

// First we have to add an effect to our actor that makes it look like he/she is casting
// we changed effects.ned so it should be ok for now.

            targetThing.AddActorEffectByLevel("ef_disc_thinblood", 2000, level, casterGuid, 4);

// DisplayCast. I never saw this before, I wonder where I can find out about this function?
// I mean, all spells FIZZLE the same (nothing happens) but actually casting a new spell will
// probably need some new code...since DisplayCast is not defined in this class ... aha, there
// it is in Discipline.class...we'll get to it later (although normally you would just jump to
// it now, I have to finish the comments on this doc).
            DisplayCast("ThinBlood", level);
// returns success, yay.
            return 1;
        }

// Ok, this is what is known as "error trapping"
// HOW on earth would you get to this code?
// If you had the power and cast if successfully, you exited with success.
// If you didnt have the power or it failed, you exited the class with failure.
// Either way, you shouldnt have come to this point in the code.
        catch(Exception e)
        {
            CodexConsole.PrintException(e.getMessage() + " in " + "ThinBlood" + " [cast]");
            return 0;
        }

// I dont understand why these functions are named the way they are. I dont know if
// automagically, the variable 'e' is created, or even when. Just change the words
// to match your discipline and move on.
        catch(Error e)
        {
            CodexConsole.PrintError(e.getMessage() + " in " + "ThinBlood" + " [cast]");
        }
        return 0;
    }

// This is NOT a function like everything else. It's a variable which will contain
// a string of letters. Let's have it contain "ThinBlood" instead :p Since this is reverse
// engineering, we are simply trying to trick the engine into thinking everything is alright.
// I mean, if it looks different to us and the engine thinks it's ok, everyone is happy :)
    private static final String DISCIPLINE_NAME = "ThinBlood";
}

][

// This thing is too goddamn big. From now on, comments will be sparse. [Jack9]
// Source File Name:   Discipline.java

public class Discipline extends Codex
{

    public void DisplayRecast(String disciplineName, int level)
    {
        String casterName = casterThing.GetName();
        int clientGuid = casterThing.GetGUID();
        String aFormat = "%C" + casterName + "%d" + disciplineName;
        CodexConsole.Print(clientGuid, 8, Codex.FormatNLS("RPG_DISCMSG_RECASTS", aFormat));
    }

// Constructor
    public Discipline()
    {
    }

    public boolean CheckCastParameters(int level, int casterGuid, String disciplineName)
    {
        if(level < 0 || level > 4)
        {
            CodexConsole.PrintError("Invalid level in Discipline " + disciplineName);
            return false;
        }
        if(!Codex.IsActorGuid(casterGuid))
        {
            CodexConsole.PrintError("Invalid caster in Discipline " + disciplineName);
            return false;
        }
        if(casterGuid != lastCasterGuid)
        {
            casterThing = new CodexActor(casterGuid);
            lastCasterGuid = casterGuid;
        }
        return true;
    }

// Here's that function. Lets work it through.
    public void DisplayCast(String disciplineName, int level)
    {
// get the caster's name
        String casterName = casterThing.GetName();
// give the caster a numerical ID
        int clientGuid = casterThing.GetGUID();
// put together the discipline name (ThinBlood for us) and the caster's name
        String aFormat = "%C" + casterName + "%d" + disciplineName;
// this prints it to the screen (remember CodexConsole.Print(), for later mods)
        CodexConsole.Print(clientGuid, 8, Codex.FormatNLS("RPG_DISCMSG_CASTS", aFormat));
    }

// more comments below.

    public void DisplayResist(String disciplineName, int level)
    {
        String targetName = targetThing.GetName();
        int clientGuid = casterThing.GetGUID();
        String aFormat = "%C" + targetName + "%d" + disciplineName;
        CodexConsole.Print(clientGuid, 0, Codex.FormatNLS("RPG_DISCMSG_RESISTED", aFormat), 0xffff00);
    }

    public boolean CheckCastTarget(int targetGuid, String disciplineName)
    {
        if(!Codex.IsActorGuid(targetGuid))
        {
            CodexConsole.PrintError("Invalid target in Discipline" + disciplineName);
            return false;
        }
        if(targetGuid != lastTargetGuid)
        {
            targetThing = new CodexActor(targetGuid);
            lastTargetGuid = targetGuid;
        }
        return true;
    }

    public void DisplayFizzle(String disciplineName, int level)
    {
        String casterName = casterThing.GetName();
        int clientGuid = casterThing.GetGUID();
        String aFormat = "%C" + casterName + "%d" + disciplineName;
        CodexConsole.Print(clientGuid, 8, Codex.FormatNLS("RPG_DISCMSG_FIZZLES", aFormat), 0xffff00);
    }

    public void DisplayNoCast(String stringId)
    {
        int clientGuid = casterThing.GetGUID();
        if(Codex.IsPlayerGuid(clientGuid))
            CodexConsole.PrintNLS(clientGuid, 0, stringId, 0xffff00);
    }

    public boolean Fizzled(int level)
    {
        if((casterThing.GetActorFlags2() & 0x200) != 0)
            return false;
        return Math.random() < (double)((float)(5 - level) / 100F);
    }

    public boolean SetupWorld(String disciplineName)
    {
        world = new CodexWorld(0xbc614e);
        if(world.GetGUID() <= 0)
        {
            CodexConsole.PrintError("Cannot find world in Discipline" + disciplineName);
            return false;
        } else
        {
            return true;
        }
    }

    protected static final int CONSOLE_FLAG_DISCIPLINECAST = 8;
    protected static final int CONSOLE_FLAG_DISCIPLINERECAST = 8;
    protected static final int CONSOLE_FLAG_DISCIPLINEFIZZLE = 8;
    protected static final int CONSOLE_FLAG_DISCIPLINERESIST = 0;
    protected static final int CONSOLE_FLAG_DISCIPLINENOCAST = 0;
    protected static final int AWE_DURATIONS[] = {
        5000, 10000, 15000, 20000, 25000
    };
    protected static final int ATROPHY_DURATIONS[] = {
        10000, 20000, 30000, 40000, 50000
    };
    protected static final int BECKONING_DURATIONS[] = {
        15000, 30000, 45000, 60000, 0x15f90
    };
    protected static final int BLOODHEALING_DURATIONS[] = {
        4000, 8000, 8000, 16000, 16000
    };
    protected static final int BLOODDEXTERITY_DURATIONS[] = {
        15000, 30000, 45000, 60000, 0x15f90
    };
    protected static final int BLOODSTRENGTH_DURATIONS[] = {
        15000, 30000, 45000, 60000, 0x15f90
    };
    protected static final int BLOODSTAMINA_DURATIONS[] = {
        15000, 30000, 45000, 60000, 0x15f90
    };
    protected static final int BLOODOFPOTENCY_DURATIONS[] = {
        15000, 30000, 45000, 60000, 0x15f90
    };
    protected static final int CELERITY_DURATIONS[] = {
        15000, 30000, 45000, 60000, 0x15f90
    };
    protected static final int CLOAKOFSHADOWS_DURATIONS[] = {
        15000, 30000, 45000, 60000, 0x15f90
    };
    protected static final int CLOAKTHEGATHERING_DURATIONS[] = {
        10000, 20000, 30000, 40000, 60000
    };
    protected static final int COMMAND_DURATIONS[] = {
        3000, 6000, 9000, 12000, 15000
    };
    protected static final int DARKHUNTER_DURATIONS[] = {
        15000, 30000, 45000, 60000, 0x15f90
    };
    protected static final int DREADGAZE_DURATIONS[] = {
        5000, 10000, 15000, 20000, 25000
    };
    protected static final int ENTRANCEMENT_DURATIONS[] = {
        9000, 12000, 15000, 18000, 21000
    };
    protected static final int EYESOFTHESERPENT_DURATIONS[] = {
        5000, 10000, 15000, 20000, 20000
    };
    protected static final int EYESOFTHEBEAST_DURATIONS[] = {
        30000, 60000, 0x15f90, 0x1d4c0, 0x249f0
    };
    protected static final int EARTHMELD_DURATIONS[] = {
        30000, 60000, 0x15f90, 0x1d4c0, 0x249f0
    };
    protected static final int FERALWHISPERS_DURATIONS[] = {
        15000, 30000, 45000, 60000, 0x15f90
    };
    protected static final int FERALCLAWS_DURATIONS[] = {
        15000, 30000, 45000, 60000, 0x15f90
    };
    protected static final int FLAMETRAIL_DURATIONS[] = {
        15000, 30000, 45000, 60000, 0x15f90
    };
// ignore this. this is for my changes to fortitude and they are incomplete.
    protected static final int FORTITUDE_DURATIONS[] = {
        0xfffff, 0xfffff, 0xfffff, 0xfffff, 0xfffff
    };
    protected static final int HATCHTHEVIPER_DURATIONS[] = {
        15000, 30000, 45000, 60000, 0x15f90
    };
    protected static final int HEARTOFSTONE_DURATIONS[] = {
        30000, 60000, 0x15f90, 0x1d4c0, 0x249f0
    };
    protected static final int HSENSES_DURATIONS[] = {
        30000, 60000, 0x15f90, 0x1d4c0, 0x249f0
    };
    protected static final int IGNOREFLAME_DURATIONS[] = {
        15000, 30000, 45000, 60000, 0x15f90
    };
    protected static final int INVISIBILITY_DURATIONS[] = {
        15000, 30000, 45000, 60000, 0x15f90
    };
    protected static final int MAJESTY_DURATIONS[] = {
        10000, 20000, 30000, 40000, 60000
    };
    protected static final int MASK1000FACES_DURATIONS[] = {
        15000, 30000, 45000, 60000, 0x124f8
    };
    protected static final int MESMERIZE_DURATIONS[] = {
        5000, 10000, 15000, 20000, 25000
    };
    protected static final int MISTFORM_DURATIONS[] = {
        15000, 30000, 45000, 60000, 0x15f90
    };
    protected static final int OBFUSCATE_DURATIONS[] = {
        15000, 30000, 45000, 60000, 0x15f90
    };
    protected static final int POSSESSION_DURATIONS[] = {
        15000, 30000, 45000, 60000, 0x15f90
    };
    protected static final int POTENCE_DURATIONS[] = {
        30000, 60000, 0x15f90, 0x1d4c0, 0x2bf20
    };
    protected static final int PRISONOFICE_DURATIONS[] = {
        2000, 4000, 6000, 8000, 10000
    };
    protected static final int PSYCHICPROJECTION_DURATIONS[] = {
        9000, 10000, 12000, 15000, 19000
    };
    protected static final int QUELLTHEBEAST_DURATIONS[] = {
        5000, 7000, 9000, 11000, 13000
    };
    protected static final int SHAMBLINGHORDES_DURATIONS[] = {
        15000, 30000, 45000, 60000, 0x15f90
    };
    protected static final int SHAPEOFTHEBEAST_DURATIONS[] = {
        15000, 30000, 45000, 60000, 0x15f90
    };
    protected static final int SKINOFTHEADDER_DURATIONS[] = {
        30000, 60000, 0x15f90, 0x1d4c0, 0x2bf20
    };
    protected static final int SUBSUMETHESPIRIT_DURATIONS[] = {
        15000, 30000, 45000, 60000, 0x15f90
    };
    protected static final int SUMMONELEMENTAL_DURATIONS[] = {
        15000, 30000, 45000, 60000, 0x15f90
    };
    protected static final int SUMMONSOUL_DURATIONS[] = {
        15000, 30000, 45000, 60000, 0x15f90
    };
    protected static final int THEFORGETFULMIND_DURATIONS[] = {
        2500, 5000, 7500, 10000, 12500
    };
    protected static final int THEHAUNTING_DURATIONS[] = {
        5000, 10000, 15000, 20000, 25000
    };

// This is a real change to the basic Discipline.class, a new array of variables.
// An array is a collection of values in 1 variable. The different values can be accessed by
// refering to the variable as THINBLOOD_DURATIONS[1] or THINBLOOD_DURATIONS[2]
// Most arrays START with THINBLOOD_DURATIONS[0], but I have a feeling the starting value is
// THINBLOOD_DURATIONS[1], which evaluates to 5000
// I copied Acid Touch, obviously

    protected static final int THINBLOOD_DURATIONS[] = {
        5000, 10000, 15000, 20000, 25000
    };

    protected static final int TORCH_DURATIONS[] = {
        15000, 30000, 45000, 60000, 0x15f90
    };
    protected static final int TRUEFAITH_DURATIONS[] = {
        2500, 5000, 7500, 10000, 12500
    };
    protected static final int TRUESIGHT_DURATIONS[] = {
        30000, 60000, 0x15f90, 0x1d4c0, 0x249f0
    };
    protected static final int VIGORMORTIS_DURATIONS[] = {
        15000, 30000, 45000, 60000, 0x15f90
    };
    protected static final int VOICEOFMADNESS_DURATIONS[] = {
        10000, 20000, 30000, 40000, 50000
    };
    protected static final float AWAKEN_HEALTHS[] = {
        0.15F, 0.3F, 0.45F, 0.6F, 0.75F
    };
    protected static final float AWAKEN_BLOODS[] = {
        0.15F, 0.15F, 0.2F, 0.2F, 0.25F
    };
    protected static final float SHAMBLINGHORDES_BLOODS[] = {
        0.05F, 0.1F, 0.15F, 0.2F, 0.25F
    };
    protected static final float SHAMBLINGHORDES_HEALTHS[] = {
        0.05F, 0.1F, 0.15F, 0.2F, 0.25F
    };
    protected static final float VIGORMORTIS_BLOODS[] = {
        0.1F, 0.2F, 0.3F, 0.4F, 0.5F
    };
    protected static final float VIGORMORTIS_HEALTHS[] = {
        0.1F, 0.2F, 0.3F, 0.4F, 0.5F
    };
    protected static final float CLOAKOFSHADOWS_ALPHA_NONE = 1F;
    protected static final float CLOAKOFSHADOWS_ALPHAS[] = {
        0.25F, 0.2F, 0.15F, 0.1F, 0.05F
    };
    protected static final float CLOAKTHEGATHERING_ALPHA_NONE = 1F;
    protected static final float CLOAKTHEGATHERING_ALPHAS[] = {
        0.25F, 0.2F, 0.15F, 0.1F, 0.05F
    };
    protected static final String FERALCLAWS_TEMPLATES[] = {
        "Claw01", "Claw02", "Claw03", "Claw04", "Claw05"
    };
    protected static final String FLASH_TEMPLATES[] = {
        "exp_flash", "exp_flash", "exp_flash", "exp_flash", "exp_flash"
    };
    protected static final int FIREBALL_DAMAGES[] = {
        10, 20, 30, 40, 50
    };
    protected static final float INVISIBILITY_ALPHA_NONE = 1F;
    protected static final float INVISIBILITY_ALPHAS[] = {
        0.25F, 0.2F, 0.15F, 0.1F, 0.05F
    };
    protected static final float MISTFORM_ALPHA_NONE = 1F;
    protected static final float MISTFORM_ALPHAS[] = {
        0.25F, 0.2F, 0.15F, 0.1F, 0.05F
    };
    protected static final float OBFUSCATE_ALPHA_NONE = 1F;
    protected static final float OBFUSCATE_ALPHAS[] = {
        0.25F, 0.2F, 0.15F, 0.1F, 0.05F
    };
    protected static final String PLAGUEWIND_TEMPLATES[] = {
        "proj_plaguewind0", "proj_plaguewind1", "proj_plaguewind2", "proj_plaguewind3", "proj_plaguewind4"
    };
    protected static final String TRUEFAITH_TEMPLATES[] = {
        "exp_truefaith", "exp_truefaith1", "exp_truefaith2", "exp_truefaith3", "exp_truefaith4"
    };
    protected static final String EYESOFTHEBEAST_TEMPLATES[] = {
        "exp_eyesofthebeast", "exp_eyesofthebeast1", "exp_eyesofthebeast2", "exp_eyesofthebeast3", "exp_eyesofthebeast4"
    };
    protected int lastCasterGuid;
    protected int lastTargetGuid;
    protected int lastWorldGuid;
    protected CodexActor casterThing;
    protected CodexActor targetThing;
    protected CodexWorld world;

}

][

// One more.
// Decompiled by Jad v1.5.7d. Copyright 2000 Pavel Kouznetsov.
// Jad home page: http://www.geocities.com/SiliconValley/Bridge/8617/jad.html
// Decompiler options: packimports(3) 
// Source File Name:   EffectDiscThinBlood.java


public class EffectDiscThinBlood extends Codex
{

// I'm fried from writing all this stuff for you guys. I dont figure any of this is important
// I'm probably very very wrong. I'm going back to the internet to distribute this and watch
// hamsterdance for awhile.

    public void effectstarted(int actorGuid, int effectGuid, int creatorGuid, int duration)
    {
        CodexActor _Target = new CodexActor(actorGuid);
        _Target.SpawnThing("invshockwave");
    }


// Constructor
    public EffectDiscAcidicTouch()
    {
    }
}

][

Exciting stuff huh?
Save your changes. Go back to the DOS window
javac *.java

Use WINZIP if possible. With winzip you can click on the 'add to archive' button and just browse
to the c:\jdk1.1.8\bin and overwrite the old classes by adding:
Discipline.class
DisciplineThinBlood.class
EffectDiscThinBlood.class

to the Codex.nob

NOTE: The rest of the discipline*.classes were ALL compiled using a different version of 
Discipline.class  This is BAD for a number of reasons that I wont go into. But simply because
we added a very minor variable to Discipline.class, I dont think it's called-for to recompile
all 241518614981 or howevermany classes that are based on the Discipline.class 
We're programmers, we're lazy, and it doesnt crash the game ^^


----------
This is as far as I've been.
Instead of working on the stuff I've written this.
I hope it proves to be a wise allocation of my time.

and more...
// Decompiled by Jad v1.5.7d. Copyright 2000 Pavel Kouznetsov.
// Jad home page: http://www.geocities.com/SiliconValley/Bridge/8617/jad.html
// Decompiler options: packimports(3) 
// Source File Name:   ItemTomeQuietus.java (modified from ItemTomeAnimalism.java)


public class ItemTomeQuietus extends Codex
{

    boolean used(int itemGuid, int userGuid, int captureId)
    {
        CodexActor user = new CodexActor(userGuid);
// I'm putting in all the disciplines right now, even if they are not functional.
// first one is Silence of Death
        if(user.GetActorDisciplineLevel("SilenceOfDeath") > -2)
        {
// PrintNLS uses something from the system.nls, GUARANTEED
            CodexConsole.PrintNLS(userGuid, 0, "DISCTOME_FAIL_QUIETUS");
// Notice the returns are true/false not 1/0  Programmers dont make much of a distinction
// Always use 1 or 0 because it's uniform, saves keystrokes, and what if the return value
// was going to be used in something silly like a calculation? Just use 1 or 0
            return false;
        } else
        {
            CodexConsole.PrintNLS(userGuid, 0, "DISCTOME_SUCCESS_QUIETUS");
// This next line is scary. It actualy gives you the power.
            user.SetActorDisciplineLevel("SilenceOfDeath", -1);
            return true;
        }
    }

    public ItemTomeQuietus()
    {
    }

    private static final String FIRST_DISCIPLINE = "SilenceOfDeath";
}

// Compiled and added to Codex.nob. Yay. I can get a tome of Quietus now, theoretically.
][