Exemple #1
0
    static void TryToBreed(gamebook.Scenario SC, critters.Critter C)
    {
        /* A breeding monster will reproduce if: */
        /*  - there are less than the max number of monsters on board */
        /*  - there is a free spot somewhere close to the breeder */

        if (critters.NumberOfCritters(SC.CList) < rpgtext.CHART_MaxMonsters)
        {
            /* Determine a direction in which to generate the new */
            /* monster. The direction can't be "5". */
            int D = rpgdice.Random(8) + 1;
            if (D > 4)
            {
                D += 1;
            }
            int X = C.M.x + texmaps.VecDir[D - 1, 0];
            int Y = C.M.y + texmaps.VecDir[D - 1, 1];

            /* Do the checks to make sure this spot is good for adding */
            /* a monster. */
            if (texmaps.OnTheMap(X, Y) && texmaps.TerrPass[SC.gb.map[X - 1, Y - 1].terr - 1] > 0)
            {
                if (!texmodel.ModelPresent(SC.gb.mog, X, Y))
                {
                    critters.AddCritter(ref SC.CList, SC.gb, C.crit, X, Y);
                }
            }
        }
    }
Exemple #2
0
    static void ActChaos(gamebook.Scenario SC, critters.Critter C)
    {
        /*The critter is gonna be acting chaotically right now.*/

        /*Determine a direction to move in. We don't want dir 5*/
        /*to be a valid choice.*/
        int D = rpgdice.Random(8) + 1;

        if (D > 4)
        {
            D += 1;
        }

        int t = 1;

        while (texmaps.TerrPass[SC.gb.map[C.M.x + texmaps.VecDir[D - 1, 0] - 1, C.M.y + texmaps.VecDir[D - 1, 1] - 1].terr - 1] < 1 && t <= 3)
        {
            D = rpgdice.Random(8) + 1;
            if (D > 4)
            {
                D += 1;
            }
            t += 1;
        }

        texmaps.WalkReport WR = WalkCritter(SC, texmaps.VecDir[D - 1, 0], texmaps.VecDir[D - 1, 1]);
        if (SC.CAct == null)
        {
            return;
        }

        if (WR.m != null)
        {
            /*Chaotic critters usually won't attack others of*/
            /*their own kind... usually. As a lazy way of*/
            /*checking this and making alliances, assume that any*/
            /*two models using the same letter to represent them*/
            /*are friendly.*/
            if (WR.m.kind == critters.MKIND_Critter && WR.m.gfx == C.M.gfx && rpgdice.Random(100) != 23)
            {
                if (texmaps.TileLOS(SC.gb.POV, C.M.x, C.M.y) && texmaps.OnTheScreen(SC.gb, C.M.x, C.M.y))
                {
                    rpgtext.DCGameMessage(critters.MonMan[C.crit - 1].name + " growls.");
                }
            }
            else if (WR.m.kind == dcchars.MKIND_Character || WR.m.kind == critters.MKIND_Critter)
            {
                if (rpgdice.Random(8) != 5)
                {
                    C.Target = WR.m;
                }

                CritterAttack(SC, C, WR.m.x, WR.m.y);
            }
        }
    }
Exemple #3
0
 static void SlimeDoNothing(gamebook.Scenario SC, critters.Critter C)
 {
     if (rpgdice.Random(64) == 9)
     {
         if (texmaps.TileLOS(SC.gb.POV, C.M.x, C.M.y) && texmaps.OnTheScreen(SC.gb, C.M.x, C.M.y))
         {
             rpgtext.DCGameMessage(critters.MonMan[C.crit - 1].name + " " + SlimeAct[rpgdice.Random(5)]);
         }
     }
 }
Exemple #4
0
    static int TacRange(critters.Critter C)
    {
        /*Given critter C, determine its effective combat range.*/
        if (C.Eqp != null && C.Eqp.ikind == dcitems.IKIND_Gun)
        {
            return(dcitems.CGuns[C.Eqp.icode - 1].RNG);
        }

        return(critters.MonMan[C.crit - 1].Range);
    }
Exemple #5
0
    static bool StatAttack(gamebook.Scenario SC, spells.SpellDesc S)
    {
        //{Affect every enemy model within range with a given}
        //{status change condition.}

        bool itworked = false;

        //{Determine the accuracy of the attack, also its Value and}
        //{Duration. Use defaults if these values can't be found.}
        int V = rpgdice.RollStep(spells.AAVal(S.ATT, spells.AA_Value));

        if (V < 5)
        {
            V = 5;
        }

        for (int X = SC.PC.m.x - S.p1; X <= SC.PC.m.x + S.p1; ++X)
        {
            for (int Y = SC.PC.m.y - S.p1; Y <= SC.PC.m.y + S.p1; ++Y)
            {
                if (texmodel.ModelPresent(SC.gb.mog, X, Y))
                {
                    critters.Critter C = critters.LocateCritter(texmodel.FindModelXY(SC.gb.mlist, X, Y), SC.CList);
                    if (C != null)
                    {
                        if (rpgdice.RollStep(S.p2) > rpgdice.RollStep(critters.MonMan[C.crit - 1].Mystic))
                        {
                            if (critters.SetCritterStatus(C, S.step, V))
                            {
                                texmaps.MapSplat(SC.gb, '*', S.c, X, Y, false);
                                itworked = true;
                            }
                        }
                    }
                }
            }
        }

        if (itworked)
        {
            rpgtext.DCAppendMessage("Done.");
            texfx.Delay();
            texmaps.DisplayMap(SC.gb);

            //{Give the PC a few points for successfully using}
            //{this spell.}
            gamebook.DoleExperience(SC, rpgdice.Random(3));
        }
        else
        {
            rpgtext.DCAppendMessage("Failed!");
        }

        return(true);
    }
Exemple #6
0
    static void CritterAttack(gamebook.Scenario SC, critters.Critter C, int TX, int TY)
    {
        /*Critter C wants to attack whatever is in square TX,TY.*/

        /*Fill out the Attack Request.*/
        dccombat.AttackRequest AR = new dccombat.AttackRequest();
        AR.Attacker = C.M;
        AR.TX       = TX;
        AR.TY       = TY;
        AR.DF       = gamebook.DF_Physical;
        AR.C        = Crt.Color.LightRed;

        /*Fill out the rest of the data dep}ant upon what equipment*/
        /*the creature is using.*/
        if (C.Eqp != null && C.Eqp.ikind == dcitems.IKIND_Gun)
        {
            AR.HitRoll = critters.MonMan[C.crit - 1].HitRoll + dcitems.CGuns[C.Eqp.icode - 1].ACC;
            AR.Damage  = dcitems.CGuns[C.Eqp.icode - 1].DMG;
            AR.Range   = dcitems.CGuns[C.Eqp.icode - 1].RNG;
            AR.ATT     = dcitems.CGuns[C.Eqp.icode - 1].ATT;

            if (AR.ATT.Contains(spells.AA_LineAttack))
            {
                AR.Desc = "fires " + dcitems.ItemNameShort(C.Eqp);
            }
            else
            {
                AR.Desc = "fires " + dcitems.ItemNameShort(C.Eqp) + " at";
            }
        }
        else if (C.Eqp != null && C.Eqp.ikind == dcitems.IKIND_Wep)
        {
            AR.HitRoll = critters.MonMan[C.crit - 1].HitRoll + dcitems.CWep[C.Eqp.icode - 1].ACC;
            AR.Damage  = critters.MonMan[C.crit - 1].Damage + dcitems.CWep[C.Eqp.icode - 1].DMG;
            AR.Range   = -1;
            AR.Desc    = "swings " + dcitems.ItemNameShort(C.Eqp) + " at";
            AR.ATT     = dcitems.CWep[C.Eqp.icode - 1].ATT;
        }
        else
        {
            AR.HitRoll = critters.MonMan[C.crit - 1].HitRoll;
            AR.Damage  = critters.MonMan[C.crit - 1].Damage;
            AR.Range   = critters.MonMan[C.crit - 1].Range;
            AR.Desc    = critters.MonMan[C.crit - 1].ADesc;
            AR.ATT     = critters.MonMan[C.crit - 1].AtAt;
        }

        /*Process the attack. If a fatality is inflicted on the*/
        /*critter's target, the Excommunicate static void will reset*/
        /*the target field to null.*/
        dccombat.ProcessAttack(SC, AR);
    }
Exemple #7
0
 static void ActHalfHunter(gamebook.Scenario SC, critters.Critter C)
 {
     /*This one is easy. Make a random roll, then branch to*/
     /*a different static void.*/
     if (rpgdice.Random(2) == 1)
     {
         ActPCHunter(SC, C);
     }
     else
     {
         ActChaos(SC, C);
     };
 }
Exemple #8
0
    static bool CritterActive(critters.Critter C)
    {
        /*Return TRUE if a given critter is capable of acting*/
        /*right now, FALSE if it is for any reason incapacitated.*/
        if (plotbase.NAttValue(C.SF, statusfx.NAG_StatusChange, statusfx.SEF_Paralysis) != 0)
        {
            return(false);
        }
        else if (plotbase.NAttValue(C.SF, statusfx.NAG_StatusChange, statusfx.SEF_Sleep) != 0)
        {
            return(false);
        }

        return(true);
    }
Exemple #9
0
    static void ActGuardian(gamebook.Scenario SC, critters.Critter C)
    {
        /*This critter is the guardian of a room.*/

        /*The guardian may try to acquire a target, or may remain in*/
        /*standby mode.*/
        if (rpgdice.Random(10) == 1)
        {
            /*Try to acquire a target.*/
            for (int X = C.M.x - critters.MonMan[C.crit - 1].Sense; X <= C.M.x + critters.MonMan[C.crit - 1].Sense; ++X)
            {
                for (int Y = C.M.y - critters.MonMan[C.crit - 1].Sense; Y <= C.M.y + critters.MonMan[C.crit - 1].Sense; ++Y)
                {
                    if (texmodel.ModelPresent(SC.gb.mog, X, Y))
                    {
                        texmodel.Model M = texmodel.FindModelXY(SC.gb.mlist, X, Y);
                        if (M.kind == dcchars.MKIND_Character)
                        {
                            ActPCHunter(SC, C);
                        }
                        else if (M.kind == critters.MKIND_Critter)
                        {
                            if (M.gfx != C.M.gfx && rpgdice.Random(3) == 1 && texmaps.CalcObscurement(C.M, M, SC.gb) > -1)
                            {
                                C.Target = M;
                            }
                        }
                    }
                }
            }
        }

        if (C.Target != null)
        {
            ActAgressive(SC, C);
        }

        if (rpgdice.Random(5) == 3)
        {
            ActChaos(SC, C);
        }
        else if (rpgdice.Random(3) == 2)
        {
            ActPassive(SC);
        }

        /*Else, just sit there and do nothing.*/
    }
Exemple #10
0
    static int RollDefenses(gamebook.Scenario SC, AttackRequest AR, int TX, int TY)
    {
        //{Roll the defenses for whatever is in location TX,TY}
        int DefRoll = 0;

        if (SC.gb.mog.IsSet(TX, TY))
        {
            //{the target is a model. Yay! Determine if it's a}
            //{critter, the PC, or something else, then look up}
            //{its defense value.}
            int DfSt = gamebook.ModelDefenseStep(SC, texmodel.FindModelXY(SC.gb.mlist, TX, TY), AR.DF);

            //{Do the defense roll. Note that unlike most rolls,}
            //{defense rolls have a minimum value.}
            DefRoll = rpgdice.RollStep(DfSt);
            if (DefRoll < DfSt)
            {
                DefRoll = DfSt;
            }

            //{While we're here, might as well do something else}
            //{altogether. If a critter is attacked, it switches its}
            //{TARGET to whatever model attacked it.}
            if (texmodel.FindModelXY(SC.gb.mlist, TX, TY).kind == critters.MKIND_Critter)
            {
                critters.Critter C = critters.LocateCritter(texmodel.FindModelXY(SC.gb.mlist, TX, TY), SC.CList);
                if (C.M != AR.Attacker)
                {
                    C.Target = AR.Attacker;
                    if (AR.Attacker.kind == dcchars.MKIND_Character)
                    {
                        SC.PC.target = texmodel.FindModelXY(SC.gb.mlist, TX, TY);
                        AlertOthers(SC, C, AR.Damage);
                    }
                }
            }
        }
        else
        {
            //{ There's no model present, meaning that we're}
            //{ firing at a map tile.It's not likely to dodge.}
            DefRoll = 0;
        }

        return(DefRoll);
    }
Exemple #11
0
    static void ActSlimy(gamebook.Scenario SC, critters.Critter C)
    {
        /*The big thing about a slime is that it never moves.*/
        /*It just sits there, and attacks whatever is within reach.*/
        /*Slimes give prefrence to attacking the PC. If the PC*/
        /*isn't nearby, it may attack other targets rpgdice.rng.Nextly.*/

        /*I just noticed something. For lower-order organisms,*/
        /*slimes sure is pretty complicated. Their behavior static void*/
        /*is the biggest one so far. Maybe that's just because I*/
        /*like them...*/

        /*If the slime has a target, then attack it.*/
        if (C.Target != null)
        {
            SlimeAttack(SC, C);
        }

        /*If the slime has no target, try to get a lock on the PC.*/
        if (GetLockOnPC(SC, C))
        {
            C.Target = SC.PC.m;
            SlimeAttack(SC, C);
        }

        /*The slime hasn't got a target. Just lash out at anything nearby!*/
        int D = rpgdice.Random(8) + 1;

        if (D > 4)
        {
            D += 1;
        }
        if (texmodel.ModelPresent(SC.gb.mog, C.M.x + texmaps.VecDir[D - 1, 0], C.M.y + texmaps.VecDir[D - 1, 1]))
        {
            /*Aha! There's a model here! Thwack it! Uhh... unless it's another slime, of course.*/
            texmodel.Model M = texmodel.FindModelXY(SC.gb.mlist, C.M.x + texmaps.VecDir[D - 1, 0], C.M.y + texmaps.VecDir[D - 1, 1]);
            if (M.gfx != C.M.gfx && M.kind == critters.MKIND_Critter)
            {
                CritterAttack(SC, C, C.M.x + texmaps.VecDir[D - 1, 0], C.M.y + texmaps.VecDir[D - 1, 1]);
            }
        }
        else
        {
            SlimeDoNothing(SC, C);
        }
    }
Exemple #12
0
 public static void UpdateMonsterMemory(Scenario SC, critters.Critter C)
 {
     //{This monster has apparently just walked into the player's}
     //{view. Update the player's Monster Memory, and maybe print}
     //{the monster's introductory text.}
     if (plotbase.NAttValue(SC.NA, plotbase.NAG_MonsterMemory, C.crit) < 100)
     {
         plotbase.AddNAtt(ref SC.NA, plotbase.NAG_MonsterMemory, C.crit, 1);
         if (plotbase.NAttValue(SC.NA, plotbase.NAG_MonsterMemory, C.crit) == 1)
         {
             SetTrigger(SC, PLT_SeeNewCritter, C.crit);
             if (critters.MonMan[C.crit - 1].IntroText != null)
             {
                 rpgtext.DCGameMessage(critters.MonMan[C.crit - 1].IntroText, true);
                 texfx.ModelFlash(SC.gb, C.M);
                 rpgtext.GamePause();
             }
         }
     }
     C.Spotted = true;
 }
Exemple #13
0
    //{*** MODEL LOOKUP FUNCTIONS ***}
    public static void Excommunicate(Scenario SC, texmodel.Model M)
    {
        //{This isn't a lookup function, but it seemed appropriate}
        //{to place it here. Model M and the thing it belongs to are}
        //{about to be removed from play. Remove all mention of this}
        //{model from game memory.}


        //{Remove all mention of this model from the Target lists}
        //{of various monsters.}
        critters.Critter CT = SC.CList;
        while (CT != null)
        {
            if (CT.Target == M)
            {
                CT.Target = null;
            }

            CT = CT.next;
        }

        //{Clear the PC's target.}
        if (SC.PC.target == M)
        {
            SC.PC.target = null;
        }

        //{Clear the active critter, if this is the active critters.}
        if (SC.CAct != null && SC.CAct.M == M)
        {
            SC.CAct = null;
        }

        //{If the next critter to act is the one who was killed,}
        //{move that pointer to the next critter in line.}
        if (SC.CA2 != null && SC.CA2.M == M)
        {
            SC.CA2 = SC.CA2.next;
        }
    }
Exemple #14
0
    static void SlimeAttack(gamebook.Scenario SC, critters.Critter C)
    {
        /*The Slime wants to attack something. Of course,*/
        /*given the fact that slimes can't move, this might*/
        /*not be possible.*/

        /*Slimes with ranged attacks may attack anyhow.*/
        if (TacRange(C) > -1 &&
            texmaps.Range(C.M, C.Target) <= critters.MonMan[C.crit - 1].Sense &&
            texmaps.CalcObscurement(C.M, C.Target, SC.gb) > -1)
        {
            CritterAttack(SC, C, C.Target.x, C.Target.y);
        }
        else if (Math.Abs(C.M.x - C.Target.x) <= 1 && Math.Abs(C.M.y - C.Target.y) <= 1)
        {
            CritterAttack(SC, C, C.Target.x, C.Target.y);
        }
        else
        {
            SlimeDoNothing(SC, C);
        }
    }
Exemple #15
0
    public static void CritterDeath(gamebook.Scenario SC, critters.Critter C, bool KilledByPC)
    {
        //{A critter has died. Deal with it.}
        if (C == null)
        {
            rpgtext.DCGameMessage("SHAZBOT - The attemptes killing of a nonexistant critters.");
            return;
        }

        //{Critters will only drop random treasure if they are killed}
        //{by the PC.}
        if (KilledByPC)
        {
            if (critters.MonMan[C.crit - 1].TType > 0)
            {
                int N = 0;
                while (N < critters.MonMan[C.crit - 1].TNum && rpgdice.Random(100) < critters.MonMan[C.crit - 1].TDrop)
                {
                    N += 1;
                    dcitems.DCItem I = charts.GenerateItem(SC, critters.MonMan[C.crit - 1].TType);
                    dcitems.PlaceDCItem(SC.gb, SC.ig, I, C.M.x, C.M.y);
                }
            }
        }

        if (C.Eqp != null && rpgdice.Random(100) < CDropEqp)
        {
            //{The critter dropped whatever it was carrying.}
            dcitems.PlaceDCItem(SC.gb, SC.ig, C.Eqp, C.M.x, C.M.y);

            //{Set the Eqp field to Nil, or else the RemoveCritter procedure}
            //{will delete the item. And mess up our map.}
            C.Eqp = null;
        }

        gamebook.Excommunicate(SC, C.M);
        critters.RemoveCritter(C, ref SC.CList, SC.gb);
    }
Exemple #16
0
    static void ProcessAlertCritters(ref string Event, gamebook.Scenario SC)
    {
        /*Alert all critters of the given type to*/
        /*the PC's presence.*/

        /* Find out what sort of critter to alert. */
        string CType = texutil.ExtractWord(ref Event);

        /* If the parameter was supplied, go on to alert those critters. */
        if (CType != "")
        {
            critters.Critter CTemp = SC.CList;
            while (CTemp != null)
            {
                if (CTemp.M.gfx == CType[0])
                {
                    CTemp.Target = SC.PC.m;
                }

                CTemp = CTemp.next;
            }
        }
    }
Exemple #17
0
    static void AlertOthers(gamebook.Scenario SC, critters.Critter C, int DMG)
    {
        //{The PC has just attacked critter C. All other critters}
        //{of this type now have a chance to target the PC for}
        //{retribution.}

        critters.Critter CTemp = SC.CList;

        while (CTemp != null)
        {
            if (CTemp.M.gfx == C.M.gfx && CTemp.Target == null && texmaps.Range(CTemp.M, C.M) < 25)
            {
                //{This critter is a contemporary of the one}
                //{which was attacked.}
                //{Check to see whether the shot was noticed.}
                if (CTemp.AIType != critters.AIT_Passive && rpgdice.RollStep(critters.MonMan[CTemp.crit - 1].Sense) > rpgdice.RollStep(dcchars.PCStealth(SC.PC) - DMG))
                {
                    CTemp.Target = SC.PC.m;
                }
            }

            CTemp = CTemp.next;
        }
    }
Exemple #18
0
    static bool GetLockOnPC(gamebook.Scenario SC, critters.Critter C)
    {
        /*The critter in question is trying to get a "lock" on*/
        /*the PC. Make a Sense roll against the PC's Stealth*/
        /*skill.*/

        /*If the player is out of range, we can't get a lock.*/
        if (texmaps.Range(C.M, SC.PC.m) > critters.MonMan[C.crit - 1].Sense * 2)
        {
            return(false);
        }

        int O = texmaps.CalcObscurement(C.M, SC.PC.m, SC.gb);

        if (O > -1)
        {
            if (rpgdice.RollStep(dcchars.PCStealth(SC.PC)) < rpgdice.RollStep(critters.MonMan[C.crit - 1].Sense) - O)
            {
                return(true);
            }
        }

        return(false);
    }
Exemple #19
0
    static void ActPCHunter(gamebook.Scenario SC, critters.Critter C)
    {
        /*The critter is gonna attempt to hunt down and destroy*/
        /*the player character, to the exclusion of all other*/
        /*targets. If the PC is not in sight, either track him*/
        /*(if within tracking range) or act passively.*/

        /*Determine whether or not the monster can get a 'lock'*/
        /*on the player. To do this, we use the monster's Sense*/
        /*rating versus the player's Stealth rating.*/
        if (GetLockOnPC(SC, C))
        {
            C.Target = SC.PC.m;
        }

        if (C.Target != null)
        {
            ActAgressive(SC, C);
        }
        else
        {
            ActPassive(SC);
        }
    }
Exemple #20
0
    static void PlayScene(gamebook.Scenario SC)
    {
        /* This procedure holds the actual game loop. */
        /* Note that at the } of this procedure, the scenario is */
        /* deallocated. */

        Crt.ClrScr();

        texmaps.UpdatePOV(SC.gb.POV, SC.gb);
        texmaps.ApplyPOV(SC.gb.POV, SC.gb);
        texmaps.DisplayMap(SC.gb);

        gamebook.PCStatLine(SC);
        SC.PC.lastCmd = ' ';

        rpgtext.DCGameMessage("Welcome to the game.");

        do
        {
            SC.ComTime += 1;

            /* Set time triggers here. */
            if (SC.ComTime % 720 == 0)
            {
                gamebook.SetTrigger(SC, "HOUR");
            }
            else if (SC.ComTime % 120 == 0)
            {
                gamebook.SetTrigger(SC, "10MIN");
            }
            else if (SC.ComTime % 12 == 0)
            {
                gamebook.SetTrigger(SC, "MINUTE");
            }

            /*Update the PC's Status List.*/
            statusfx.UpdateStatusList(ref SC.PC.SF);

            /*Check the PCs food status. A check is performed*/
            /*every 10 minutes.*/
            if (SC.ComTime % 120 == 81)
            {
                if (SC.PC.carbs > -10)
                {
                    SC.PC.carbs -= 1;
                }
                if (SC.PC.carbs < 0)
                {
                    rpgtext.DCGameMessage("You are starving!");
                }
                else if (SC.PC.carbs < 10)
                {
                    rpgtext.DCGameMessage("You are hungry.");
                }

                gamebook.PCStatLine(SC);
            }

            /* Check for PC regeneration. A check is performed every minute. */
            /* The PC does _not_ regenerate while poisoned. Ouch. */
            if (SC.ComTime % 12 == 0)
            {
                /*See if the PC gets any HPs back this click...*/
                if (SC.PC.HP < SC.PC.HPMax && plotbase.NAttValue(SC.PC.SF, statusfx.NAG_StatusChange, statusfx.SEF_Poison) == 0)
                {
                    if (gamebook.NumberOfActions(SC.ComTime / 12, dcchars.PCRegeneration(SC.PC)) > 0)
                    {
                        SC.PC.HP += gamebook.NumberOfActions(SC.ComTime / 12, dcchars.PCRegeneration(SC.PC));

                        /*If the PC is starving and injured, perminant damage to health may result.*/
                        if (SC.PC.carbs < 0 && rpgdice.Random(Math.Abs(SC.PC.carbs)) > rpgdice.Random(SC.PC.stat[8 - 1]) && SC.PC.HPMax > 10)
                        {
                            SC.PC.HPMax -= 1;
                            rpgtext.DCGameMessage("You feel seriously ill.");
                        }

                        if (SC.PC.HP > SC.PC.HPMax)
                        {
                            SC.PC.HP = SC.PC.HPMax;
                        }

                        gamebook.PCStatLine(SC);
                    }
                }

                /*Check for PC MP restoration.*/
                if (SC.PC.MP < SC.PC.MPMax)
                {
                    SC.PC.MP += gamebook.NumberOfActions(SC.ComTime / 12, dcchars.PCRestoration(SC.PC));
                    if (SC.PC.MP > SC.PC.MPMax)
                    {
                        SC.PC.MP = SC.PC.MPMax;
                    }

                    gamebook.PCStatLine(SC);
                }
            }

            /*Check for random monsters every 5 minutes.*/
            if (SC.ComTime % rpgtext.PLAY_MonsterTime == 0)
            {
                charts.WanderingCritters(SC);
            }

            /* Check for spontaneous identification of items every hour. */
            if (SC.ComTime % 720 == 553)
            {
                pcaction.ScanUnknownInv(SC);
            }


            /*If the player gets an action this second, use it.*/
            for (int t = 1; t <= gamebook.NumberOfActions(SC.ComTime, dcchars.PCMoveSpeed(SC.PC)); ++t)
            {
                DoPCAction(SC);

                /* If QUIT was the command, or if the PC is dead, */
                /* break this loop. */
                if (SC.PC.lastCmd == rpgtext.KMap[26].key || SC.PC.HP <= 0)
                {
                    break;
                }

                plotline.HandleTriggers(SC);

                SC.gb.POV.range = dcchars.PCVisionRange(SC.PC);
            }

            /* If a QUIT request wan't recieved, handle clouds and critters. */
            if (SC.PC.lastCmd != rpgtext.KMap[26].key)
            {
                /*Cloud handling. Happens every 4 seconds.*/
                if (SC.ComTime % 4 == 1)
                {
                    cbrain.BrownianMotion(SC);
                }

                /*Critter handling*/
                critters.Critter Cr = SC.CList;
                while (Cr != null)
                {
                    /*Save the position of the next critter,*/
                    /*since the critter we're processing might*/
                    /*accidentally kill itself during its move.*/
                    SC.CA2 = Cr.next;
                    for (int t = 1; t <= gamebook.NumberOfActions(SC.ComTime, critters.MonMan[Cr.crit - 1].Speed); ++t)
                    {
                        cbrain.CritterAction(SC, ref Cr);
                        if (Cr == null)
                        {
                            break;
                        }
                    }

                    Cr = SC.CA2;
                    if (SC.PC.HP < 1)
                    {
                        Cr = null;
                    }
                }
            }
        }while (SC.PC.lastCmd != rpgtext.KMap[26].key && SC.PC.HP > 0);

        if (SC.PC.HP < 1)
        {
            rpgtext.DCGameMessage("Game Over.");
            rpgtext.GamePause();

            string fname = "savegame/" + SC.PC.name + ".txt";

            if (rpgtext.PLAY_DangerOn)
            {
                File.Delete(fname);
            }
        }
    }
Exemple #21
0
    static bool DamageCritter(gamebook.Scenario SC, critters.Critter C, int MOS, AttackRequest AR, int DMG, ref AttackReport Rep)
    {
        //{Damages a critters. Returns TRUE if the critter has been}
        //{destroyed; returns FALSE if it is still functional.}

        //var
        // OriginalDamage,E,N,V,Armor: int;
        // snuffedit: bool;

        //{Save the original damage}
        int OriginalDamage = DMG;

        //{Scale damage for elemental types.}
        //{First, determine what element is being invoked.}
        int E = spells.AAVal(AR.ATT, spells.AA_Element);

        DMG = critters.ScaleCritterDamage(C, DMG, E);

        //{Scale damage for critter slaying attribute.}
        E = spells.AAVal(AR.ATT, spells.AA_Slaying);

        if (E > 0 && critters.MonMan[C.crit - 1].CT.Contains(critters.CTMan[E - 1]))
        {
            if (DMG < OriginalDamage)
            {
                DMG = OriginalDamage;
            }
            DMG *= 2 + rpgdice.Random(3);
        }

        //{Reduce damage for armor, and increase it for condition.}
        if (DMG > 0)
        {
            //{If a critter is asleep, then it will take double damage}
            //{from a successful hit and be woken up if it survives.}
            if (plotbase.NAttValue(C.SF, statusfx.NAG_StatusChange, statusfx.SEF_Sleep) != 0)
            {
                DMG *= 2;
                plotbase.SetNAtt(ref C.SF, statusfx.NAG_StatusChange, statusfx.SEF_Sleep, 0);
            }

            //{Calculate Armor rating.}
            int Armor = critters.MonMan[C.crit - 1].Armor;

            //{Reduce for MOS}
            if (MOS > 0)
            {
                if (MOS > 4)
                {
                    MOS = 4;
                }
                Armor = (Armor * (4 - MOS)) / 4;
                if (texmaps.TileLOS(SC.gb.POV, C.M.x, C.M.y))
                {
                    rpgtext.DCAppendMessage("Critical Hit!");
                }
            }

            //{Reduce for Armor-Piercing}
            if (AR.ATT.Contains(spells.AA_ArmorDoubling))
            {
                Armor *= 2;
            }
            else if (AR.ATT.Contains(spells.AA_ArmorPiercing))
            {
                Armor = (Armor + 1) / 2;
            }

            DMG -= Armor;
            if (DMG < 1)
            {
                DMG = 1;
            }
        }

        C.HP -= DMG;
        bool snuffedit = true;

        if (C.HP > 0)
        {
            //{ The target is still alive. See what else needs to be done.}
            snuffedit = false;

            //{ There may be status change effects here.}
            E = spells.AAVal(AR.ATT, spells.AA_StatusChange);
            if (E != 0)
            {
                int N = spells.AAVal(AR.ATT, spells.AA_HitRoll);
                if (N == 0 || rpgdice.RollStep(N) > rpgdice.RollStep(critters.MonMan[C.crit - 1].Mystic))
                {
                    int v = rpgdice.RollStep(spells.AAVal(AR.ATT, spells.AA_Value));
                    if (v < 5)
                    {
                        v = 5;
                    }
                    if (critters.SetCritterStatus(C, -E, v) && texmaps.TileLOS(SC.gb.POV, C.M.x, C.M.y))
                    {
                        rpgtext.DCAppendMessage(statusfx.NegSFName[E - 1] + "!");
                    }
                }
            }
        }
        else
        {
            snuffedit = true;

            //{ Add the XPV of the critter to the Attack Report's XPV field.}
            Rep.XPV = Rep.XPV + critters.MonMan[C.crit - 1].XPV;
            CritterDeath(SC, C, AR.Attacker == SC.PC.m);
        }

        return(snuffedit);
    }
Exemple #22
0
    /*This unit handles critter behavior and stuff.*/

    public static void CritterAction(gamebook.Scenario SC, ref critters.Critter C)
    {
        if (C.HP < 0)
        {
            Crt.Write("ERROR- We caught a dead critter acting..!\n");
            do
            {
                rpgtext.RPGKey();
            } while (true);
        }

        /*Critter C is about to perform some sort of action. Yay!*/
        /*Decide what it's gonna do based on its AI type.*/
        SC.CAct = C;

        if (CritterActive(C))
        {
            if (critters.MonMan[C.crit - 1].CT.Contains(critters.XCT_Breeder) && rpgdice.Random(15) == 1)
            {
                TryToBreed(SC, C);
            }
            else if (C.Target != null && C.AIType != critters.AIT_Slime)
            {
                ActAgressive(SC, C);
            }
            else
            {
                switch (C.AIType)
                {
                case critters.AIT_Passive: ActPassive(SC); break;

                case critters.AIT_PCHunter: ActPCHunter(SC, C); break;

                case critters.AIT_Chaos: ActChaos(SC, C); break;

                case critters.AIT_Guardian: ActGuardian(SC, C); break;

                case critters.AIT_Slime: ActSlimy(SC, C); break;

                case critters.AIT_HalfHunter: ActHalfHunter(SC, C); break;
                }
            }
        }

        /* Protect against the creature already being dead here. */
        if (SC.CAct != null)
        {
            /*Update the critter's status.*/
            if (plotbase.NAttValue(C.SF, statusfx.NAG_StatusChange, statusfx.SEF_Poison) != 0)
            {
                C.HP -= rpgdice.Random(6);
            }

            statusfx.UpdateStatusList(ref C.SF);

            if (C.HP < 0)
            {
                dccombat.CritterDeath(SC, C, false);
            }
        }

        C       = SC.CAct;
        SC.CAct = null;
    }
Exemple #23
0
    static void ActAgressive(gamebook.Scenario SC, critters.Critter C)
    {
        /*This critter apparently has a target. Try to get as*/
        /*close to it as possible.*/

        /*Check, first of all, that we have a target.*/
        if (C.Target == null)
        {
            ActPassive(SC);
            return;
        }

        /*Next, on a random whim, check to make sure the target is*/
        /*still visible.*/
        if (rpgdice.Random(3) == 1 && C.Target == SC.PC.m && !C.Spotted)
        {
            int O = texmaps.CalcObscurement(C.M, C.Target, SC.gb);
            if (O == -1 || O > critters.MonMan[C.crit - 1].Sense)
            {
                C.Target = null;
                ActPassive(SC);
                return;
            }
        }
        else if (rpgdice.Random(10) == 3)
        {
            if (C.HP >= critters.MonMan[C.crit - 1].MaxHP)
            {
                int O = texmaps.CalcObscurement(C.M, C.Target, SC.gb);
                if (O == -1 || O > critters.MonMan[C.crit - 1].Sense)
                {
                    C.Target = null;
                    ActPassive(SC);
                    return;
                }
            }
        }

        /*Check to see whether or not our critter is gonna try a missile attack.*/
        if (TacRange(C) > 0 && rpgdice.Random(2) == 1 && texmaps.CalcObscurement(C.M, C.Target, SC.gb) > -1)
        {
            /* In addition to the above qualifiers, the critter will */
            /* only use a missile attack if its target is within visual */
            /* range or if it can be seen by the PC. */
            if (texmaps.Range(C.M, C.Target) < critters.MonMan[C.crit - 1].Sense || texmaps.TileLOS(SC.gb.POV, C.M.x, C.M.x))
            {
                CritterAttack(SC, C, C.Target.x, C.Target.y);
                return;
            }
        }

        /*We aren't gonna try a missile attack.*/
        /*Move towards the target.*/
        int DX = 0;
        int DY = 0;

        if (C.Target.x < C.M.x)
        {
            DX = -1;
        }
        else if (C.Target.x > C.M.x)
        {
            DX = 1;
        }

        if (C.Target.y < C.M.y)
        {
            DY = -1;
        }
        else if (C.Target.y > C.M.y)
        {
            DY = 1;
        }

        /*Check to see if we're in attack range.*/
        if (C.M.x + DX != C.Target.x || C.M.y + DY != C.Target.y)
        {
            /*Check for obstructions*/
            if (!MoveOK(SC, C.M.x + DX, C.M.y + DY))
            {
                if (MoveOK(SC, C.M.x + DX, C.M.y))
                {
                    DY = 0;
                }
                else if (MoveOK(SC, C.M.x, C.M.y + DY))
                {
                    DX = 0;
                }
                else if (rpgdice.Random(2) == 1)
                {
                    ActPassive(SC);
                    return;
                }
            }
        }

        texmaps.WalkReport WR = WalkCritter(SC, DX, DY);
        if (SC.CAct == null)
        {
            return;
        }

        if (WR.m != null)
        {
            /*The critter has walked into a model. Decide*/
            /*whether or not to attack.*/

            /*If the model is in the same square as the critter's target,*/
            /*it will be attacked. Before I just used to compare the*/
            /*target model with WR.M, but since adding clouds to the game*/
            /*I have to compare the position of WR.M to the position of*/
            /*the int}ed target. This is important just in case the*/
            /*critter is attempting to attack a hallucination-inducing*/
            /*cloud, and instead blunders into one of its own buddies...*/

            if (WR.m.x == C.Target.x && WR.m.y == C.Target.y)
            {
                CritterAttack(SC, C, WR.m.x, WR.m.y);
            }
        }
    }
Exemple #24
0
    public static void WanderingCritters(gamebook.Scenario SC)
    {
        //{Add some random monsters to the map, if appropriate.}

        //{Decide how many random generations we're gonna perform.}
        int N = critters.NumberOfCritters(SC.CList);

        if (N >= MaxMonsters)
        {
            return;
        }

        int Gen = 0;

        if (critters.NumberOfCritters(SC.CList) < MaxMonsters / 2)
        {
            Gen = rpgtext.CHART_NumGenerations + rpgdice.Random(rpgtext.CHART_NumGenerations);
        }
        else
        {
            Gen = rpgdice.Random(rpgtext.CHART_NumGenerations) + 1;
        }

        while (Gen > 0)
        {
            Gen -= 1;

            //{Check to see if there is any room for more monsters.}
            //{The more monsters we have, the less likely we are to add more.}
            if (critters.NumberOfCritters(SC.CList) < rpgdice.Random(MaxMonsters / 2) + (MaxMonsters / 2) + 1)
            {
                //{Roll on the random monster chart.}
                //{ First decide what chart to use. Either pick a chart }
                //{ based on PC level, or use the "signature chart" for }
                //{ the currrent location. }
                int Chart;
                if (rpgdice.Random(3) != 1)
                {
                    //{ Pick chart based on level. }
                    Chart = (rpgdice.Random(SC.PC.lvl) / 3) + 1;
                }
                else
                {
                    //{ The Signature Charts start at 1 and go down. }
                    Chart = 2 - SC.Loc_Number;
                }

                //{ Range check the selected chart... }
                if (Chart > NumWChart)
                {
                    Chart = NumWChart;
                }
                else if (Chart < 1)
                {
                    Chart = 1;
                }

                //{ Roll the Entry and Number. }
                int E = rpgdice.Random(NumWCT);
                N = rpgdice.Random(WanderChart[Chart - 1, E, 1]) + 1;

                //{Decide upon a nice place to put our critters.}
                //{Select an origin spot - the generated critters will be centered here.}
                int X0 = rpgdice.Random(texmodel.XMax) + 1;
                int Y0 = rpgdice.Random(texmodel.YMax) + 1;

                //{We're gonna give up if we can't find an appropriate}
                //{tile after 10,000 tries.}
                int tries = 0;
                while (texmaps.TerrPass[SC.gb.map[X0 - 1, Y0 - 1].terr - 1] < 1 && tries < 10000)
                {
                    X0    += 1;
                    tries += 0;

                    if (X0 > texmodel.XMax)
                    {
                        Y0 += 1;
                        X0  = 1;
                    }
                    if (Y0 > texmodel.YMax)
                    {
                        Y0 = 1;
                    }
                }

                for (int t = 1; t <= N; t++)
                {
                    //{Starting position for the swarm is the origin determined earlier.}
                    int X = X0;
                    int Y = Y0;

                    //{Check to see if this is an appropriate spot.}
                    tries = 0;
                    while (tries < 10 && !GoodSpot(SC, X, Y))
                    {
                        tries += 1;
                        X     += rpgdice.Random(3) - rpgdice.Random(3);
                        if (X < 1)
                        {
                            X = 1;
                        }
                        else if (X > texmodel.XMax)
                        {
                            X = texmodel.XMax;
                        }

                        Y += rpgdice.Random(3) - rpgdice.Random(3);
                        if (Y < 1)
                        {
                            Y = 1;
                        }
                        else if (Y > texmodel.YMax)
                        {
                            Y = texmodel.YMax;
                        }
                    }

                    //{If we have a good spot, render the monster.}
                    //{Otherwise, just forget it.}
                    if (GoodSpot(SC, X, Y))
                    {
                        critters.Critter C = critters.AddCritter(ref SC.CList, SC.gb, WanderChart[Chart - 1, E, 0], X, Y);

                        //{Check to see whether the monster is equipped with a weapon.}
                        if (C != null && critters.MonMan[C.crit - 1].EType > 0 && rpgdice.Random(100) < critters.MonMan[C.crit - 1].EChance)
                        {
                            C.Eqp = GenerateItem(SC, critters.MonMan[C.crit - 1].EType);
                        }
                    }
                }
            }
        }
    }