Exemplo n.º 1
0
    public override bool OnEndCombat(GameObject attachee, GameObject triggerer)
    {
        if (attachee.IsUnconscious())
        {
            return(RunDefault);
        }

        var curr = attachee.GetStat(Stat.hp_current) - attachee.GetStat(Stat.subdual_damage);
        var maxx = attachee.GetStat(Stat.hp_max);
        var xx   = attachee.GetLocation() & (65535);
        var hp_percent_lareth = 100 * curr / maxx;
        var ggv400            = GetGlobalVar(400);
        var ggv401            = GetGlobalVar(401);

        if (!GetGlobalFlag(834))
        {
            if (((ggv401 >> 15) & 7) == 1)
            {
                var closest_distance_1 = SelectedPartyLeader.DistanceTo(attachee);
                foreach (var pc in GameSystems.Party.PartyMembers)
                {
                    closest_distance_1 = Math.Min(closest_distance_1, pc.DistanceTo(attachee));
                }

                if (closest_distance_1 <= 25 || xx > 480)
                {
                    for (var ppq = 3; ppq < 26; ppq++)
                    {
                        StartTimer(ppq * 2500 + RandomRange(0, 20), () => OnStartCombat(attachee, triggerer, true, ppq), true);
                    }

                    ggv401 += 1 << 15;
                    SetGlobalVar(401, ggv401);
                }
            }
        }

        // Wake up sleeping guy script
        var bbb = attachee.GetInt(obj_f.critter_strategy);

        if (bbb == 80)                            // if using the 'seek beacon' strategy
        {
            bbb = attachee.GetInt(obj_f.pad_i_0); // retrieve previous strat
            attachee.SetInt(obj_f.critter_strategy, bbb);
            foreach (var obj in ObjList.ListCone(attachee, ObjectListFilter.OLC_NPC, 20, 0, 360))
            {
                if ((14074..14078).Contains(obj.GetNameId()) && obj != attachee)
                {
                    var obj_pad3 = obj.GetInt(obj_f.npc_pad_i_3);
                    if ((obj_pad3 & (0x100)) != 0) // is a beacon object
                    {
                        obj.Destroy();
                    }
                }
            }
        }

        // if can_see_party(attachee):
        // flash_signal(10)
        // attachee.obj_set_int(obj_f_critter_strategy, 82)
        // game.timevent_add(san_end_combat, ( attachee, triggerer, 1), 300, 1)
        // else:
        // if can_see_party(attachee):
        // flash_signal(10)
        // attachee.obj_set_int(obj_f_critter_strategy, 82)
        return(RunDefault);
    }
Exemplo n.º 2
0
    public bool OnStartCombat(GameObject attachee, GameObject triggerer, bool generated_from_timed_event_call, int talk_stage)
    {
        if (attachee.IsUnconscious())
        {
            return(RunDefault);
        }

        // if !generated_from_timed_event_call and attachee.distance_to( party_closest(attachee) ) > 45:
        // attachee.move( party_closest(attachee).location, 0 , 0)
        // for pp in range(0, 41):
        // attachee.scripts[pp] = 998
        // game.leader.ai_follower_add(attachee)
        // #game.timevent_add( lareth_abandon, (attachee, triggerer), 20, 1)
        var curr = attachee.GetStat(Stat.hp_current) - attachee.GetStat(Stat.subdual_damage);
        var maxx = attachee.GetStat(Stat.hp_max);
        var xx   = attachee.GetLocation() & (65535);
        var hp_percent_lareth = 100 * curr / maxx;
        var ggv400            = GetGlobalVar(400);
        var ggv401            = GetGlobalVar(401);
        var pad3 = attachee.GetInt(obj_f.npc_pad_i_3);

        if ((attachee.GetMap() == 5005) && (party_too_far_from_lareth(attachee)) && !generated_from_timed_event_call)
        {
            if (((pad3 & 0x4) == 0))
            {
                // Delay for one round, letting him cast Shield of Faith - he'll need it :)
                pad3 |= 0x4;
                attachee.SetInt(obj_f.npc_pad_i_3, pad3);
                return(RunDefault);
            }

            // Party is too far from Lareth, gotta nudge him in the right direction
            // spawn a beacon and change Lareth's strat to approach it
            locXY beacon_loc;
            if (xx > 478)
            {
                beacon_loc = new locXY(498, 550);
            }
            else
            {
                beacon_loc = new locXY(487, 540);
            }

            var obj_beacon = GameSystems.MapObject.CreateObject(14074, beacon_loc);
            obj_beacon.SetObjectFlag(ObjectFlag.DONTDRAW);
            obj_beacon.SetObjectFlag(ObjectFlag.CLICK_THROUGH);
            obj_beacon.Move(beacon_loc, 0, 0);
            obj_beacon.SetBaseStat(Stat.dexterity, -30);
            obj_beacon.SetInt(obj_f.npc_pad_i_3, 0x100);
            obj_beacon.Attack(SelectedPartyLeader);
            obj_beacon.AddToInitiative();
            attachee.SetInt(obj_f.pad_i_0, attachee.GetInt(obj_f.critter_strategy)); // Record original strategy
            attachee.SetInt(obj_f.critter_strategy, 80);                             // set Lareth's strat to "seek beacon"
            var grease_detected = false;
            foreach (var spell_obj in ObjList.ListCone(attachee, ObjectListFilter.OLC_GENERIC, 40, 0, 360))
            {
                // Check for active GREASE spell object
                if (spell_obj.GetInt(obj_f.secretdoor_dc) == 200 + (1 << 15))
                {
                    grease_detected = true;
                }
            }

            if (grease_detected)
            {
                // In case Lareth slips and doesn't execute his san_end_combat (wherein the beacon object is destroyed) - spawn a couple of timed events to guarantee the beacon doesn't survive
                StartTimer(3700, () => kill_beacon_obj(obj_beacon, attachee), true);
                StartTimer(3900, () => kill_beacon_obj(obj_beacon, attachee), true);
            }

            return(RunDefault);
        }

        // strategy 81 - Approach Party strategy
        if (attachee.GetInt(obj_f.critter_strategy) == 81 && !generated_from_timed_event_call)
        {
            if (ScriptDaemon.can_see_party(attachee))
            {
                attachee.SetInt(obj_f.critter_strategy, 82);
            }
        }

        if (attachee.GetInt(obj_f.critter_strategy) != 81 && !generated_from_timed_event_call)
        {
            // Should Lareth cast Obscuring Mist?
            // First, find closest party member - the most likely target for an archer
            var closest_pc_1 = SelectedPartyLeader;
            foreach (var pc in PartyLeader.GetPartyMembers())
            {
                if (pc.DistanceTo(attachee) < closest_pc_1.DistanceTo(attachee))
                {
                    closest_pc_1 = pc;
                }
            }

            // Then, check for spell objects with the Obscuring Mist ID, which are also identified as active
            var player_in_obscuring_mist = 0;
            foreach (var spell_obj in ObjList.ListCone(closest_pc_1, ObjectListFilter.OLC_GENERIC, 30, 0, 360))
            {
                if (spell_obj.GetInt(obj_f.secretdoor_dc) == 333 + (1 << 15) && spell_obj.DistanceTo(closest_pc_1) <= 17.5f)
                {
                    player_in_obscuring_mist = 1;
                }
            }

            var player_cast_web      = false;
            var player_cast_entangle = false;
            foreach (var spell_obj in ObjList.ListVicinity(attachee.GetLocation(), ObjectListFilter.OLC_GENERIC))
            {
                if (spell_obj.GetInt(obj_f.secretdoor_dc) == 531 + (1 << 15))
                {
                    player_cast_web = true;
                }

                if (spell_obj.GetInt(obj_f.secretdoor_dc) == 153 + (1 << 15))
                {
                    player_cast_entangle = true;
                }
            }

            // Assess level of ranged weapon threat
            var ranged_threat = 0;
            foreach (var pc in PartyLeader.GetPartyMembers())
            {
                var pc_weap = pc.ItemWornAt(EquipSlot.WeaponPrimary).GetInt(obj_f.weapon_type);
                if ((new[] { 14, 17, 46, 48, 68 }).Contains(pc_weap) && !pc.IsUnconscious())
                {
                    // 14 - light crossbow
                    // 17 - heavy crossbow
                    // 46 - shortbow
                    // 48 - longbow
                    // 68 - repeating crossbow
                    if (ranged_threat == 0)
                    {
                        ranged_threat = 1;
                    }

                    if (pc.HasFeat(FeatId.POINT_BLANK_SHOT) || (pc.GetStat(Stat.level_fighter) + pc.GetStat(Stat.level_ranger)) >= 1)
                    {
                        if (ranged_threat < 2)
                        {
                            ranged_threat = 2;
                        }
                    }

                    if (pc.HasFeat(FeatId.PRECISE_SHOT) && (pc.GetStat(Stat.level_fighter) + pc.GetStat(Stat.level_ranger)) >= 1)
                    {
                        if (ranged_threat < 3)
                        {
                            ranged_threat = 3;
                        }
                    }
                }
            }

            if ((attachee.GetMap() == 5005 && xx > 478) && (((ggv401 >> 25) & 3) == 0) && ((ranged_threat == 3) || (ranged_threat > 1 && player_in_obscuring_mist == 1) || (ranged_threat > 0 && (player_cast_entangle || player_cast_web))))
            {
                // Cast Obscuring Mist, if:
                // 1. Haven't cast it yet  - (ggv401 >> 25) & 3
                // 2. Ranged threat exists (emphasized when player casts web or is in obscuring mist)
                // Give him a potion of Obscuring Mist, to simulate him having that scroll (just like I do...)
                if (attachee.FindItemByProto(8899) == null)
                {
                    attachee.GetItem(GameSystems.MapObject.CreateObject(8899, attachee.GetLocation()));
                }

                ggv401 += 1 << 25;
                SetGlobalVar(401, ggv401);
                var lareth_is_threatened = 0;
                if (closest_pc_1.DistanceTo(attachee) <= 3)
                {
                    lareth_is_threatened = 1;
                }

                if (lareth_is_threatened == 1)
                {
                    attachee.SetInt(obj_f.critter_strategy, 85); // Obscuring Mist + 5ft step
                }
                else
                {
                    attachee.SetInt(obj_f.critter_strategy, 86); // Just Obscuring Mist
                }
            }
            else if (((pad3 & (2)) == 0) && (player_cast_entangle || player_cast_web))
            {
                attachee.SetInt(obj_f.critter_strategy, 87); // Dispel strat
                pad3 |= (2);
                attachee.SetInt(obj_f.npc_pad_i_3, pad3);
            }
            else if (attachee.GetMap() == 5005 && player_entrenched_in_corridor(attachee))
            {
                attachee.SetInt(obj_f.critter_strategy, 89);
            }
            else
            {
                attachee.SetInt(obj_f.critter_strategy, 82);
            }
        }

        if ((hp_percent_lareth < 50) && (!generated_from_timed_event_call || generated_from_timed_event_call && talk_stage == 667))
        {
            if ((ggv400 & (0x40)) == 0)
            {
                GameObject found_pc = null;
                var        obj_list = new List <GameObject>();
                using var firstList = ObjList.ListVicinity(attachee.GetLocation(), ObjectListFilter.OLC_NPC);
                obj_list.AddRange(firstList);

                // Extending the range a little...
                foreach (var obj in ObjList.ListVicinity(attachee.GetLocation().OffsetTiles(-35, 0), ObjectListFilter.OLC_NPC))
                {
                    if (!((obj_list).Contains(obj)))
                    {
                        obj_list.Add(obj);
                    }
                }

                foreach (var obj in ObjList.ListVicinity(attachee.GetLocation().OffsetTiles(35, 0), ObjectListFilter.OLC_NPC))
                {
                    if (!((obj_list).Contains(obj)))
                    {
                        obj_list.Add(obj);
                    }
                }

                foreach (var obj in obj_list)
                {
                    foreach (var pc in SelectedPartyLeader.GetPartyMembers())
                    {
                        if (pc.type == ObjectType.pc && !pc.IsUnconscious())
                        {
                            found_pc = pc;
                        }

                        obj.AIRemoveFromShitlist(pc);
                        obj.SetReaction(pc, 50);
                        obj.RemoveFromInitiative();
                        if (pc.type == ObjectType.npc)
                        {
                            pc.AIRemoveFromShitlist(obj);
                        }
                    }

                    foreach (var obj2 in ObjList.ListVicinity(attachee.GetLocation(), ObjectListFilter.OLC_ALL))
                    {
                        if (obj2.type == ObjectType.pc || obj2.type == ObjectType.npc)
                        {
                            obj2.SetReaction(obj, 50);
                            try
                            {
                                obj2.AIRemoveFromShitlist(obj);
                            }
                            finally
                            {
                                var dummy = 1;
                            }

                            obj2.RemoveFromInitiative();
                        }
                    }
                }

                if (!generated_from_timed_event_call)
                {
                    StartTimer(100, () => OnStartCombat(attachee, triggerer, true, 667), true);
                }
                else if (found_pc != null)
                {
                    ggv400 |= 0x40;
                    SetGlobalVar(400, ggv400);
                    SetGlobalFlag(834, true);
                    found_pc.BeginDialog(attachee, 160);
                    return(SkipDefault);
                }
            }
        }
        else if (!generated_from_timed_event_call && !GetGlobalFlag(834))
        {
            if (((ggv401 >> 15) & 7) == 0)
            {
                ggv401 += 1 << 15;
                SetGlobalVar(401, ggv401);
            }
            else if (((ggv401 >> 15) & 7) == 1)
            {
                var closest_distance_1 = SelectedPartyLeader.DistanceTo(attachee);
                foreach (var pc in GameSystems.Party.PartyMembers)
                {
                    closest_distance_1 = Math.Min(closest_distance_1, pc.DistanceTo(attachee));
                }

                if (closest_distance_1 < 45)
                {
                    for (var ppq = 3; ppq < 26; ppq++)
                    {
                        StartTimer(ppq * 2500 + RandomRange(0, 20), () => OnStartCombat(attachee, triggerer, true, ppq), true);
                    }

                    ggv401 += 1 << 15;
                    SetGlobalVar(401, ggv401);
                }
            }
        }
        else if (generated_from_timed_event_call && !GetGlobalFlag(834))
        {
            if ((hp_percent_lareth > 75) && (ggv400 & 0x10) == 0 && !attachee.D20Query(D20DispatcherKey.QUE_Prone))
            {
                if (talk_stage >= 3 && ((ggv401 >> 15) & 31) == 2)
                {
                    attachee.FloatLine(6000, triggerer);
                    Sound(4201, 1);
                    Sound(4201, 1);
                    ggv401 += 1 << 15;
                    SetGlobalVar(401, ggv401);
                }
                else if (talk_stage >= 3 && ((ggv401 >> 15) & 31) == 3)
                {
                    Sound(4202, 1);
                    Sound(4202, 1);
                    ggv401 += 1 << 15;
                    SetGlobalVar(401, ggv401);
                }
                else if (talk_stage >= 3 && ((ggv401 >> 15) & 31) == 4)
                {
                    Sound(4203, 1);
                    Sound(4203, 1);
                    ggv401 += 1 << 15;
                    SetGlobalVar(401, ggv401);
                }
                else if (talk_stage >= 8 && ((ggv401 >> 15) & 31) == 5)
                {
                    attachee.FloatLine(6001, triggerer);
                    Sound(4204, 1);
                    Sound(4204, 1);
                    ggv401 += 1 << 15;
                    SetGlobalVar(401, ggv401);
                }
                else if (talk_stage >= 8 && ((ggv401 >> 15) & 31) == 6)
                {
                    Sound(4205, 1);
                    Sound(4205, 1);
                    ggv401 += 1 << 15;
                    SetGlobalVar(401, ggv401);
                }
                else if (talk_stage >= 13 && ((ggv401 >> 15) & 31) == 7)
                {
                    attachee.FloatLine(6002, triggerer);
                    Sound(4206, 1);
                    Sound(4206, 1);
                    ggv401 += 1 << 15;
                    SetGlobalVar(401, ggv401);
                }
                else if (talk_stage >= 13 && ((ggv401 >> 15) & 31) == 8)
                {
                    Sound(4207, 1);
                    Sound(4207, 1);
                    ggv401 += 1 << 15;
                    SetGlobalVar(401, ggv401);
                }
                else if (talk_stage >= 18 && ((ggv401 >> 15) & 31) == 9)
                {
                    attachee.FloatLine(6003, triggerer);
                    Sound(4208, 1);
                    Sound(4208, 1);
                    ggv401 += 1 << 15;
                    SetGlobalVar(401, ggv401);
                }
                else if (talk_stage >= 18 && ((ggv401 >> 15) & 31) == 10)
                {
                    Sound(4209, 1);
                    Sound(4209, 1);
                    ggv401 += 1 << 15;
                    SetGlobalVar(401, ggv401);
                }
                else if (talk_stage >= 22 && ((ggv401 >> 15) & 31) == 11)
                {
                    attachee.FloatLine(6004, triggerer);
                    Sound(4210, 1);
                    Sound(4210, 1);
                    ggv401 += 1 << 15;
                    SetGlobalVar(401, ggv401);
                }
                else if (talk_stage >= 22 && ((ggv401 >> 15) & 31) == 12)
                {
                    attachee.FloatLine(6004, triggerer);
                    Sound(4211, 1);
                    Sound(4211, 1);
                    ggv401 += 1 << 15;
                    SetGlobalVar(401, ggv401);
                }
                else if (talk_stage >= 22 && ((ggv401 >> 15) & 31) == 13)
                {
                    attachee.FloatLine(6004, triggerer);
                    Sound(4212, 1);
                    Sound(4212, 1);
                    ggv401 += 1 << 15;
                    SetGlobalVar(401, ggv401);
                }
            }
            else if ((hp_percent_lareth <= 75) && (ggv400 & 0x10) == 0)
            {
                if (((ggv401 >> 15) & 31) > 2)
                {
                    attachee.FloatLine(6005, triggerer);
                    Sound(4200, 1);
                    Sound(4200, 1);
                }

                StartTimer(5500, () => OnStartCombat(attachee, triggerer, true, 667), true);
                ggv400 |= 0x10;
                SetGlobalVar(400, ggv400);
            }
        }

        // Spiritual Weapon Shenanigens	#
        CombatStandardRoutines.Spiritual_Weapon_Begone(attachee);
        return(RunDefault);
    }