Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /**
- * Perk: Mysterious Stranger - Main code
- *
- * Description: Check perk_ms_h.fos
- * Author: Slowhand
- * Reviewer: n/a
- */
- #include "perk_ms_h.fos"
- #include "_defines.fos"
- #include "_basetypes.fos"
- #include "_scripts.fos"
- #include "_macros.fos"
- #include "_dialogs.fos"
- #include "_ai.fos"
- #include "npc_common.fos"
- /**<
- * Cooldown / Perk availability checks
- */
- bool isMsReadyToSpawn(uint playerId)
- {
- if (isMsSpawned(playerId)) {
- MS_LOG("Mysterious Stranger is already spawned.");
- return false;
- }
- if (!isMsNormalSpawnAvailable(playerId)) {
- MS_LOG("Mysterious Stranger is busy.");
- return false;
- }
- if (isMsDead(playerId)) {
- MS_LOG("Mysterious Stranger is dead.");
- return false;
- }
- return true;
- }
- /**< Check this function to control which maps shall MS appear. By default maps with Town Control should be disabled. */
- bool isMsAvailableOnMap(uint playerId)
- {
- Critter@ player = GetCritter(playerId);
- if (valid(player))
- {
- Map@ map = player.GetMap();
- string mapName = "";
- map.ProtoName(mapName);
- MS_LOG("Map proto name = " + mapName + ", ID = " + map.GetProtoId());
- // Adding exceptions where the MS may not spawn.
- for (uint i = 0; i < disabledMsMaps.length(); i++)
- {
- if (mapName == disabledMsMaps[i])
- {
- MS_LOG("MS is not allowed on this map.");
- return false;
- }
- }
- }
- return true;
- }
- bool doesPlayerHaveMsPerk(uint playerId)
- {
- Critter@ player = GetCritter(playerId);
- if (!valid(player))
- return false;
- if (player.Perk[PE_MYSTERIOUS_STRANGER] > 0)
- return true;
- else
- return false;
- }
- bool shallMsSpawnOnEncounter(uint playerId)
- {
- if (isMsReadyToSpawn(playerId)
- && isMsAvailableOnMap(playerId))
- {
- Critter@ player = GetCritter(playerId);
- int chance = MS_ENC_BASE_CHANCE;
- chance += player.Stat[ST_CHARISMA] * MS_ENC_CHA_CHANCE_FACTOR;
- chance += player.Stat[ST_LUCK] * MS_ENC_LK_CHANCE_FACTOR;
- chance = CLAMP(chance, MS_ENC_MIN_CHANCE, MS_ENC_MAX_CHANCE);
- int roll = Random(0, 100);
- MS_LOG("Shall MS spawn for Encounter? (Chance >= Roll) : (" + chance + ", " + roll + ")");
- if (chance >= roll)
- return true;
- else
- return false;
- }
- else
- {
- MS_LOG("MS cannot be spawned for Encounter.");
- return false;
- }
- }
- /**< If this check is called, it will disable positive checks and it will start a timer which will re-enable positives checks. */
- bool shallMsSpawnForFirstAid(uint playerId)
- {
- if (isMsReadyToSpawn(playerId)
- && isMsFirstAidAvailable(playerId)
- && isMsMedicalSpawnAvailable(playerId)
- && isMsAvailableOnMap(playerId))
- {
- Critter@ player = GetCritter(playerId);
- int chance = MS_FA_BASE_CHANCE;
- chance += player.Stat[ST_CHARISMA] * player.Stat[ST_LUCK] * MS_FA_CHANCE_FACTOR;
- chance = CLAMP(chance, MS_FA_MIN_CHANCE, MS_FA_MAX_CHANCE);
- int roll = Random(0, 100);
- MS_LOG("Shall MS spawn for First Aid? (Chance >= Roll) : (" + chance + ", " + roll + ")");
- if (chance >= roll)
- return true;
- else
- return false;
- }
- else
- {
- MS_LOG("MS cannot be spawned for First Aid call.");
- return false;
- }
- }
- bool shallMsSpawnForDoctor(uint playerId)
- {
- if (isMsReadyToSpawn(playerId)
- && isMsDoctorAvailable(playerId)
- && isMsMedicalSpawnAvailable(playerId)
- && isMsAvailableOnMap(playerId))
- {
- Critter@ player = GetCritter(playerId);
- int chance = MS_DOC_BASE_CHANCE;
- chance += player.Stat[ST_CHARISMA] * player.Stat[ST_LUCK] * MS_DOC_CHANCE_FACTOR;
- chance = CLAMP(chance, MS_DOC_MIN_CHANCE, MS_DOC_MAX_CHANCE);
- int roll = Random(0, 100);
- MS_LOG("Shall MS spawn for Doctor? (Chance >= Roll) : (" + chance + ", " + roll + ")");
- if (chance >= roll)
- return true;
- else
- return false;
- }
- else
- {
- MS_LOG("MS cannot be spawned for Doctor call.");
- return false;
- }
- }
- /**<
- * If this check is called, it will disable positive checks on medical call
- * and it will start a timer which will re-enable positives checks.
- * Shall be called on both call success and failure.
- */
- void blockMsMedicalSpawnRepeatedChecks(uint playerId)
- {
- MS_LOG("Blocking medical spawn availability against call spam.");
- setMsMedicalSpawnAvailability(playerId, false);
- startMsMedicalSpawnTimer(playerId, getMsMedicalSpawnBlockTimerDuration(playerId));
- }
- /**< */
- /**<
- * Init Mysterious Stranger game variables when perk is given the first time.
- */
- void givePlayerMsPerkInit(uint playerId)
- {
- MS_LOG("Give MS perk for player - Init game varialbes.");
- initMsPerk(playerId);
- return;
- }
- void initMsPerk(uint playerId)
- {
- setMsDead(playerId, false);
- setMsNormalSpawnAvailability(playerId, true);
- // These 2 variables are a check for MS not to be able to FA/Doctor more than once in a session.
- setMsDoctorAvailability(playerId, true);
- setMsFirstAidAvailability(playerId, true);
- // This timer is a protection timer for MS not to trigger a spawn chance whenever crippled/low hp and attacked each time in a short duration.
- setMsMedicalSpawnAvailability(playerId, true);
- }
- /**< */
- /**<
- * Spawn entry points.
- * Only use these spawning functions according to purpose, because of timers/variables and other logic is linked to these.
- */
- void spawnMysteriousStrangerForEncounter(uint playerId)
- {
- if (shallMsSpawnOnEncounter(playerId))
- {
- MS_LOG("MS is being spawned for Encounter.");
- spawnMysteriousStranger(playerId);
- startMsNormalSpawnTimer(playerId, getMsNormalSpawnTimerDuration(playerId));
- startMsHelpDurationTimer(playerId, getMsHelpDuration(playerId));
- }
- else
- {
- MS_LOG("MS was not ready to be spawned for encounter.");
- }
- }
- void spawnMysteriousStrangerForFirstAid(uint playerId)
- {
- if (shallMsSpawnForFirstAid(playerId))
- {
- MS_LOG("MS is being spawned for First Aid.");
- spawnMysteriousStranger(playerId);
- startMsNormalSpawnTimer(playerId, getMsNormalSpawnTimerDuration(playerId));
- startMsHelpDurationTimer(playerId, getMsHelpDuration(playerId));
- Critter@ ms = GetCritter(getMsId(playerId));
- Critter@ player = GetCritter(playerId);
- if (valid(ms) && valid(player))
- {
- ms.Say(SAY_NORM_ON_HEAD, "Dude! You are bleeding!");
- AddHealCritterPlane(ms, 90, player, true);
- setMsFirstAidAvailability(playerId, false);
- }
- else
- {
- MS_LOG("MS did not spawn for some reason for First Aid call, even though all checks were successful.");
- }
- }
- else
- {
- MS_LOG("MS was not ready to be spawned for First Aid.");
- }
- if (isMsMedicalSpawnAvailable(playerId))
- {
- blockMsMedicalSpawnRepeatedChecks(playerId);
- }
- }
- void spawnMysteriousStrangerForDoctor(uint playerId)
- {
- if (shallMsSpawnForDoctor(playerId))
- {
- MS_LOG("MS is being spawned for Doctor.");
- spawnMysteriousStranger(playerId);
- startMsNormalSpawnTimer(playerId, getMsNormalSpawnTimerDuration(playerId));
- startMsHelpDurationTimer(playerId, getMsHelpDuration(playerId));
- Critter@ ms = GetCritter(getMsId(playerId));
- Critter@ player = GetCritter(playerId);
- if (valid(ms) && valid(player))
- {
- ms.Say(SAY_NORM_ON_HEAD, "It's first day at the clinic all over again.");
- AddDoctorCritterPlane(ms, 90, player, true);
- setMsDoctorAvailability(playerId, false);
- }
- else
- {
- MS_LOG("MS did not spawn for some reason for Doctor call, even though all checks were successful.");
- }
- }
- else
- {
- MS_LOG("MS was not ready to be spawned for Doctor.");
- }
- if (isMsMedicalSpawnAvailable(playerId))
- {
- blockMsMedicalSpawnRepeatedChecks(playerId);
- }
- }
- /**<
- * Inner spawning and despawning function, do not call these directly, except for tests.
- */
- /**<
- * Since MS does not support multiple spawning per player, some timer logic and CD check remains here,
- * also these are shared between all the possible spawns, maybe those be regular or special.
- */
- bool spawnMysteriousStranger(uint playerId)
- {
- Critter@ player = GetCritter(playerId);
- MS_LOG("Mysterious Stranger is ready to be spawned.");
- uint mobX = player.HexX + Random(-2, 2);
- uint mobY = player.HexY + Random(-2, 2);
- int[] params =
- {
- ST_TEAM_ID, 0,
- ST_NPC_ROLE, 0,
- ST_DIALOG_ID, DIALOG_perk_ms_description,
- ST_AI_ID, MS_AI_PACK_USED
- };
- Map@ map = player.GetMap();
- uint16 msPid = getMsModelPid(playerId);
- Critter@ ms = map.AddNpc(msPid, mobX, mobY, 1, params, null, "perk_ms@ms_init");
- if (valid(ms))
- {
- setMsSpawned(playerId, true);
- setMsId(playerId, ms.Id);
- ms.SpawnedBy = playerId;
- personalizeMs(ms);
- ms.Say(SAY_NORM, "Have no fear, The Stranger is here!");
- }
- return true;
- }
- bool despawnMysteriousStranger(uint playerId)
- {
- uint msId = getMsId(playerId);
- Critter@ ms = GetCritter(msId);
- if (valid(ms))
- {
- ms.TransitToGlobal(false);
- DeleteNpc(ms);
- MS_LOG("Transiting to Global and recycling.");
- }
- else
- {
- MS_LOG("MS was already recycled!");
- }
- setMsSpawned(playerId, false);
- return true;
- }
- /**< */
- /**< Aux function */
- uint16 getMsModelPid(uint playerId)
- {
- Critter@ player = GetCritter(playerId);
- if (player.Stat[ST_CHARISMA] < 4)
- {
- return MS_PID_LEVEL1;
- }
- if (player.Stat[ST_CHARISMA] < 7)
- {
- return MS_PID_LEVEL2;
- }
- int[] reputations = {FACTION_BOS, FACTION_ENCLAVE, FACTION_NCR, FACTION_GUNRUNNERS};
- int repIndex = findHighestReputationIndexIn(playerId, reputations);
- switch (repIndex)
- {
- case FACTION_BOS:
- return MS_PID_LEVEL3_BOS;
- case FACTION_ENCLAVE:
- return MS_PID_LEVEL3_ENC;
- case FACTION_NCR:
- return MS_PID_LEVEL3_NRC;
- case FACTION_GUNRUNNERS:
- return MS_PID_LEVEL3_GR;
- default:
- return MS_PID_LEVEL3_GR;
- }
- return MS_PID_LEVEL3_GR;
- }
- int findHighestReputationIndexIn(uint playerId, array<int>& params)
- {
- Critter@ player = GetCritter(playerId);
- if (!valid(player))
- return 0;
- if (params.length() < 1)
- return 0;
- int highestRepIndex = 0;
- for (uint i = 1; i < params.length(); i++)
- {
- if (player.Reputation[i] > player.Reputation[highestRepIndex])
- {
- highestRepIndex = i;
- }
- }
- return highestRepIndex;
- }
- void personalizeMs(Critter& ms)
- {
- Critter@ player = GetCritter(ms.SpawnedBy);
- if (player.Stat[ST_CHARISMA] < 4)
- {
- setBaseStatsForMsLevel(ms, 0);
- setExtraStatsForMsLevel(ms, 0);
- setInventoryForMsLevel1(ms);
- equipMsWeapon(ms, PID_COMBAT_SHOTGUN);
- }
- else if (player.Stat[ST_CHARISMA] < 7)
- {
- setBaseStatsForMsLevel(ms, 1);
- setExtraStatsForMsLevel(ms, 1);
- setInventoryForMsLevel2(ms);
- }
- else
- {
- setBaseStatsForMsLevel(ms, 2);
- setExtraStatsForMsLevel(ms, 2);
- setInventoryForMsLevel3(ms);
- }
- }
- void setBaseStatsForMsLevel(Critter& ms, int bonus)
- {
- // Stats
- ms.StatBase[ST_STRENGTH] = 6 + bonus;
- ms.StatBase[ST_PERCEPTION] = 6 + bonus;
- ms.StatBase[ST_ENDURANCE] = 6 + bonus;
- ms.StatBase[ST_CHARISMA] = 4 + bonus;
- ms.StatBase[ST_INTELLECT] = 6 + bonus;
- ms.StatBase[ST_AGILITY] = 8 + bonus;
- ms.StatBase[ST_LUCK] = 3 + 2 * bonus;
- ms.StatBase[ST_ACTION_POINTS] = 9 + bonus;
- ms.StatBase[ST_CURRENT_AP] = ms.StatBase[ST_ACTION_POINTS];
- // Skills
- ms.SkillBase[SK_SMALL_GUNS] = 100;
- ms.SkillBase[SK_BIG_GUNS] = 100;
- ms.SkillBase[SK_ENERGY_WEAPONS] = 100;
- ms.SkillBase[SK_DOCTOR] = 50;
- ms.SkillBase[SK_FIRST_AID] = 75;
- // Traits and perks
- ms.TraitBase[TRAIT_FAST_SHOT] = 1;
- Critter@ player = GetCritter(ms.SpawnedBy);
- if (valid(player) && Random(0, 10) >= player.Stat[ST_LUCK] * 3)
- {
- ms.TraitBase[TRAIT_JINXED] = 1;
- }
- else
- {
- ms.TraitBase[TRAIT_BONEHEAD] = 1;
- }
- // Absorbs
- ms.StatBase[ST_NORMAL_ABSORB] = 5 + 5 * bonus;
- ms.StatBase[ST_FIRE_ABSORB] = 5 + 5 * bonus;
- ms.StatBase[ST_LASER_ABSORB] = 10 + 5 * bonus;
- ms.StatBase[ST_PLASMA_ABSORB] = 5 + 5 * bonus;
- ms.StatBase[ST_EXPLODE_ABSORB] = 10 + 5 * bonus;
- ms.StatBase[ST_ELECTRO_ABSORB] = 5 + 5 * bonus;
- // Resists
- ms.StatBase[ST_NORMAL_RESIST] = 5 + 25 * bonus;
- ms.StatBase[ST_FIRE_RESIST] = 15 + 25 * bonus;
- ms.StatBase[ST_LASER_RESIST] = 35 + 25 * bonus;
- ms.StatBase[ST_PLASMA_RESIST] = 5 + 25 * bonus;
- ms.StatBase[ST_EXPLODE_RESIST] = 15 + 25 * bonus;
- ms.StatBase[ST_ELECTRO_RESIST] = 5 + 25 * bonus;
- }
- void setExtraStatsForMsLevel(Critter& ms, int bonus)
- {
- Critter@ player = GetCritter(ms.SpawnedBy);
- int level = CLAMP(player.Stat[ST_LEVEL] + 3, 3, 24 + bonus * 3);
- ms.StatBase[ST_MAX_LIFE] += CLAMP(level * (4 + bonus * 3), 0, 300);
- ms.StatBase[ST_CURRENT_HP] = ms.StatBase[ST_MAX_LIFE];
- ms.SkillBase[SK_SMALL_GUNS] += CLAMP(level * (2 + bonus) , 0, 150);
- ms.SkillBase[SK_BIG_GUNS] += CLAMP(level * (2 + bonus), 0, 150);
- ms.SkillBase[SK_ENERGY_WEAPONS] += CLAMP(level * (2 + bonus), 0, 150);
- MS_LOG("MS SKILL(extra setup): SK_SMALL_GUNS = (" + ms.SkillBase[SK_SMALL_GUNS] + ", " + ms.Skill[SK_SMALL_GUNS] + ").");
- ms.SkillBase[SK_FIRST_AID] += CLAMP(level * (2 + bonus), 0, 150);
- MS_LOG("MS SKILL: SK_FIRST_AID = (" + ms.SkillBase[SK_FIRST_AID] + ", " + ms.Skill[SK_FIRST_AID] + ").");
- ms.SkillBase[SK_DOCTOR] += CLAMP(level * (1 + bonus), 0, 100);
- MS_LOG("MS SKILL: SK_DOCTOR = (" + ms.SkillBase[SK_DOCTOR] + ", " + ms.Skill[SK_DOCTOR] + ").");
- ms.StatBase[ST_ACTION_POINTS] += CLAMP(level / 12 * (1+ bonus), 0, 6);
- MS_LOG("MS STATS: ST_ACTION_POINTS = (" + ms.StatBase[ST_ACTION_POINTS] + ", " + ms.Stat[ST_ACTION_POINTS] + ").");
- if (level >= 3) ms.PerkBase[PE_ADRENALINE_RUSH] = 1;
- if (level >= 6) ms.PerkBase[PE_IRON_GRIP] = 1;
- if (level >= 9) ms.PerkBase[PE_EVEN_TOUGHER] = 1;
- if (level >= 12) ms.PerkBase[PE_BONUS_RANGED_DAMAGE] = 1;
- if (level >= 15) ms.PerkBase[PE_LIVING_ANATOMY] = 1;
- if (level >= 18) ms.PerkBase[PE_BONUS_RATE_OF_FIRE] = 1;
- if (level >= 21) ms.PerkBase[PE_STONEWALL] = 1;
- if (level >= 24) ms.PerkBase[PE_MORE_RANGED_DAMAGE] = 1;
- if (level >= 27) ms.PerkBase[PE_MORE_CRITICALS] = 1;
- if (level >= 30) ms.PerkBase[PE_EVEN_MORE_CRITICALS] = 1;
- }
- void setInventoryForMsLevel1(Critter& ms)
- {
- Critter@ player = GetCritter(ms.SpawnedBy);
- int level = CLAMP(player.Stat[ST_LEVEL] + 3, 3, 24);
- if (level < 8)
- {
- ms.AddItem(PID_SHOTGUN, 1);
- ms.AddItem(PID_SHOTGUN_SHELLS, 2 + 2 * level);
- } else if (level < 16)
- {
- ms.AddItem(PID_COMBAT_SHOTGUN, 1);
- ms.AddItem(PID_SHOTGUN_SHELLS, 12 + 3 * level);
- }
- else
- {
- ms.AddItem(PID_HK_CAWS, 1);
- ms.AddItem(PID_SHOTGUN_SHELLS, 12 + 4 * level);
- }
- ms.AddItem(PID_STIMPAK, level / 4);
- ms.AddItem(PID_LEATHER_JACKET, 1);
- ms.AddItem(PID_LEATHER_JACKET_HELMET, 1);
- }
- void setInventoryForMsLevel2(Critter& ms)
- {
- Critter@ player = GetCritter(ms.SpawnedBy);
- int level = CLAMP(player.Stat[ST_LEVEL] + 3, 3, 27);
- if (level < 9)
- {
- ms.AddItem(PID_ASSAULT_RIFLE, 1);
- ms.AddItem(PID_5MM_AP, 36 + 12 * level);
- } else if (level < 18)
- {
- ms.AddItem(PID_FN_FAL, 1);
- ms.AddItem(PID_7_62MM_AMMO, 20 + 10 * level);
- }
- else
- {
- ms.AddItem(PID_FN_FAL_HPFA, 1);
- ms.AddItem(PID_7_62MM_AMMO, 20 + 20 * level);
- }
- ms.AddItem(PID_SUPER_STIMPAK, level / 8);
- ms.AddItem(PID_LEATHER_ARMOR, 1);
- ms.AddItem(PID_LEATHER_ARMOR_HELMET, 1);
- }
- void setInventoryForMsLevel3(Critter& ms)
- {
- Critter@ player = GetCritter(ms.SpawnedBy);
- int level = CLAMP(player.Stat[ST_LEVEL] + 3, 3, 30);
- if (level < 10)
- {
- ms.AddItem(PID_LASER_RIFLE, 1);
- ms.AddItem(PID_MICRO_FUSION_CELL, 12 + 3 * level);
- }
- else if (level < 20)
- {
- ms.AddItem(PID_PLASMA_RIFLE, 1);
- ms.AddItem(PID_MICRO_FUSION_CELL, 12 + 3 * level);
- }
- else
- {
- ms.AddItem(PID_GATLING_LASER, 1);
- ms.AddItem(PID_MICRO_FUSION_CELL, 30 + 5 * level);
- }
- ms.AddItem(PID_PSYCHO, 1);
- ms.AddItem(PID_BUFFOUT, 1);
- ms.AddItem(PID_MENTATS, 1);
- ms.AddItem(PID_SUPER_STIMPAK, level / 6);
- ms.AddItem(PID_LEATHER_ARMOR, 1);
- ms.AddItem(PID_LEATHER_ARMOR_HELMET, 1);
- }
- bool equipMsWeapon(Critter& ms, uint16 protoId)
- {
- array<Item@> items;
- uint num = ms.GetItems(SLOT_INV, items);
- for (uint i = 0; i < items.length(); i++)
- {
- if (items[i].GetProtoId() == protoId)
- {
- ms.MoveItem(items[i].Id, 1, SLOT_HAND1);
- return true;
- }
- }
- return false;
- }
- /**< */
- /**< Timers */
- /**< Timer creation */
- void startMsNormalSpawnTimer(uint playerId, int durationInRealSeconds)
- {
- uint[] values = {playerId};
- setMsNormalSpawnAvailability(playerId, false);
- CreateTimeEvent(AFTER(REAL_SECOND(durationInRealSeconds)), "e_resetMsNormalSpawnTimer", values, true);
- MS_LOG("MS normal spawn timer created and started.");
- }
- void startMsMedicalSpawnTimer(uint playerId, int durationInRealSeconds)
- {
- uint[] values = {playerId};
- setMsMedicalSpawnAvailability(playerId, false);
- CreateTimeEvent(AFTER(REAL_SECOND(durationInRealSeconds)), "e_resetMsMedicalSpawnTimer", values, true);
- MS_LOG("MS medical spawn timer created and started.");
- }
- void startMsDeathTimer(uint playerId, int durationInRealSeconds)
- {
- uint[] values = {playerId};
- setMsDead(playerId, true);
- CreateTimeEvent(AFTER(REAL_SECOND(durationInRealSeconds)), "e_resetMsDeathTimer", values, true);
- MS_LOG("MS death timer created and started.");
- }
- void startMsHelpDurationTimer(uint playerId, int durationInRealSeconds)
- {
- uint[] values = {playerId};
- CreateTimeEvent(AFTER(REAL_SECOND(durationInRealSeconds)), "e_despawnMsDueToRtModeTimeout", values, true);
- MS_LOG("MS help duration timer created and started.");
- }
- /**< Timer duration configurations, should be changed for balance at each server */
- int getMsNormalSpawnTimerDuration(uint playerId)
- {
- Critter@ player = GetCritter(playerId);
- return MS_BASE_RESPAWN_CD / player.Stat[ST_CHARISMA];
- }
- int getMsMedicalSpawnBlockTimerDuration(uint playerId)
- {
- Critter@ player = GetCritter(playerId);
- return MS_BASE_MEDICAL_SPAWN_BLOCK_CD / player.Stat[ST_CHARISMA];
- }
- int getMsDeathTimer(uint playerId)
- {
- Critter@ player = GetCritter(playerId);
- return MS_BASE_DEATH_CD / player.Stat[ST_CHARISMA];
- }
- int getMsHelpDuration(uint playerId)
- {
- Critter@ player = GetCritter(playerId);
- return MS_BASE_RT_DURATION + MS_RT_DURATION_FACTOR * player.Stat[ST_CHARISMA];
- }
- /**<
- * Timer events
- */
- uint e_resetMsNormalSpawnTimer(array<uint>@ values)
- {
- uint playerId = values[0];
- MS_LOG("Normal spawn timer ended. Mysterious Stranger is ready to be spawned again.");
- setMsNormalSpawnAvailability(playerId, true);
- setMsFirstAidAvailability(playerId, true);
- setMsDoctorAvailability(playerId, true);
- return 0;
- }
- uint e_resetMsMedicalSpawnTimer(array<uint>@ values)
- {
- uint playerId = values[0];
- MS_LOG("Medical spawn timer ended. Mysterious Stranger is ready to be spawned on FA or Doctor check again.");
- setMsMedicalSpawnAvailability(playerId, true);
- return 0;
- }
- uint e_resetMsDeathTimer(array<uint>@ values)
- {
- uint playerId = values[0];
- MS_LOG("Death timer ended. Mysterious Stranger is ready to be spawned again.");
- setMsDead(playerId, false);
- return 0;
- }
- uint e_despawnMsDueToRtModeTimeout(array<uint>@ values)
- {
- uint playerId = values[0];
- MS_LOG("MS RT mode availability ended.");
- despawnMysteriousStranger(playerId);
- return 0;
- }
- /**< */
- /**<
- * Mysterious Stranger specific local game variable handling
- */
- bool isMsSpawned(uint playerId)
- {
- return isGameVarSet(playerId, LVAR_perk_ms_spawned);
- }
- void setMsSpawned(uint playerId, bool isSpawned)
- {
- setGameVarToBooleanValue(playerId, LVAR_perk_ms_spawned, isSpawned);
- }
- uint getMsId(uint playerId)
- {
- return getGameVar(playerId, LVAR_perk_ms_id);
- }
- void setMsId(uint playerId, uint id)
- {
- setGameVarToValue(playerId, LVAR_perk_ms_id, id);
- }
- bool isMsNormalSpawnAvailable(uint playerId)
- {
- MS_LOG("MS normal spawn availability is " + isGameVarSet(playerId, LVAR_perk_ms_normal_timer));
- return isGameVarSet(playerId, LVAR_perk_ms_normal_timer);
- }
- void setMsNormalSpawnAvailability(uint playerId, bool isAvailable)
- {
- setGameVarToBooleanValue(playerId, LVAR_perk_ms_normal_timer, isAvailable);
- }
- bool isMsMedicalSpawnAvailable(uint playerId)
- {
- MS_LOG("MS medical spawn availability is " + isGameVarSet(playerId, LVAR_perk_ms_medical_timer));
- return isGameVarSet(playerId, LVAR_perk_ms_medical_timer);
- }
- void setMsMedicalSpawnAvailability(uint playerId, bool isAvailable)
- {
- setGameVarToBooleanValue(playerId, LVAR_perk_ms_medical_timer, isAvailable);
- }
- bool isMsDead(uint playerId)
- {
- return isGameVarSet(playerId, LVAR_perk_ms_dead);
- }
- void setMsDead(uint playerId, bool isDead)
- {
- setGameVarToBooleanValue(playerId, LVAR_perk_ms_dead, isDead);
- }
- bool isMsFirstAidAvailable(uint playerId)
- {
- MS_LOG("MS First Aid availability is " + isGameVarSet(playerId, LVAR_perk_ms_first_aid_available));
- return isGameVarSet(playerId, LVAR_perk_ms_first_aid_available);
- }
- void setMsFirstAidAvailability(uint playerId, bool isAvailable)
- {
- setGameVarToBooleanValue(playerId, LVAR_perk_ms_first_aid_available, isAvailable);
- }
- bool isMsDoctorAvailable(uint playerId)
- {
- MS_LOG("MS Doctor availability is " + isGameVarSet(playerId, LVAR_perk_ms_doctor_available));
- return isGameVarSet(playerId, LVAR_perk_ms_doctor_available);
- }
- void setMsDoctorAvailability(uint playerId, bool isAvailable)
- {
- setGameVarToBooleanValue(playerId, LVAR_perk_ms_doctor_available, isAvailable);
- }
- /**< */
- /**<
- * Generic local game variable handlers
- */
- bool isGameVarSet(uint critterId, uint16 varId)
- {
- GameVar@ gameVar = GetLocalVar(varId, critterId);
- if (!valid(gameVar))
- return false;
- if (gameVar.GetValue() == 0)
- return false;
- else
- return true;
- }
- void setGameVarToBooleanValue(uint critterId, uint16 varId, bool value)
- {
- GameVar@ gameVar = GetLocalVar(varId, critterId);
- if (!valid(gameVar))
- return;
- if (value)
- gameVar = 1;
- else
- gameVar = 0;
- }
- int getGameVar(uint critterId, uint16 varId)
- {
- GameVar@ gameVar = GetLocalVar(varId, critterId);
- if (!valid(gameVar))
- return 0;
- return gameVar.GetValue();
- }
- void setGameVarToValue(uint critterId, uint16 varId, int value)
- {
- GameVar@ gameVar = GetLocalVar(varId, critterId);
- if (!valid(gameVar))
- return;
- gameVar = value;
- }
- /**< */
- /**<
- * Script setup
- */
- void ms_init(Critter& cr, bool firstTime)
- {
- cr.StatBase[ST_REPLICATION_TIME] = REPLICATION_DELETE;
- cr.SetEvent(CRITTER_EVENT_SMTH_ATTACKED, "_MsSmthAttacked");
- cr.SetEvent(CRITTER_EVENT_ATTACKED, "_MsAttacked");
- cr.SetEvent(CRITTER_EVENT_DEAD, "_MsDead");
- cr.SetEvent(CRITTER_EVENT_IDLE, "_MsIdle");
- }
- /**< */
- /**<
- * Combat events for Mysterious Stranger NPC.
- */
- void _MsSmthAttacked(Critter& ms, Critter& fromCr, Critter& attacker)
- {
- // If the attacked target is the owner (Player)
- if(valid(ms) && fromCr.Id == ms.SpawnedBy)
- {
- Critter@ player = fromCr;
- // cr.Say(SAY_NORM, "Owner under attack!");
- MS_LOG("MS: Owner under attack!");
- if (isCritterBelowHalfHp(player))
- {
- if (isMsFirstAidAvailable(player.Id))
- {
- ms.Say(SAY_NORM_ON_HEAD, "Don't worry, let me heal you " + player.Name + "!");
- MS_LOG("Owner bellow half HP.");
- // add code to heal master here
- AddHealCritterPlane(ms, 100, player, true);
- setMsFirstAidAvailability(player.Id, false);
- }
- else
- {
- if (Random(0, 5) == 0)
- ms.Say(SAY_NORM_ON_HEAD, "Heal yourself " + player.Name + "!");
- MS_LOG("Owner bellow half HP, but first aid not available.");
- }
- }
- if (isCritterCrippled(player))
- {
- if (isMsDoctorAvailable(player.Id))
- {
- ms.Say(SAY_NORM_ON_HEAD, "Oh boy, oh boy... Let me patch you up " + player.Name + "!");
- MS_LOG("Owner is crippled.");
- // add code to heal master here
- AddDoctorCritterPlane(ms, 90, player, true);
- setMsDoctorAvailability(player.Id, false);
- }
- }
- // Add attacker to target list, if not already there
- if (!ms.CheckEnemyInStack(attacker.Id))
- {
- if (Random(0, 3) == 0)
- ms.Say(SAY_NORM_ON_HEAD, "Look! Another target!");
- MS_LOG("MS: Adding attacker to enemy stack.");
- ms.AddEnemyInStack(attacker.Id);
- AddAttackPlane(ms, 80, attacker, true);
- }
- }
- // If the attacker is the owner, add target to target list.
- if (valid(ms) && attacker.Id == ms.SpawnedBy)
- {
- MS_LOG("MS: Owner is targeting something!");
- if (!ms.CheckEnemyInStack(fromCr.Id))
- {
- if (Random(0, 2) == 0)
- ms.Say(SAY_NORM_ON_HEAD, "You point, I punch.. err.. shoot!");
- MS_LOG("MS: Adding target of owner to enemy stack.");
- ms.AddEnemyInStack(fromCr.Id);
- AddAttackPlane(ms, 80, fromCr, true);
- }
- }
- }
- bool _MsAttacked(Critter& ms, Critter& attacker)
- {
- ms.AddEnemyInStack(attacker.Id);
- MS_LOG("MS under attack.");
- return true;
- }
- void _MsDead(Critter& ms, Critter@ killer)
- {
- Critter@ player = GetCritter(ms.SpawnedBy);
- MS_LOG("My Mysterious Stranger was killed!");
- startMsDeathTimer(player.Id, getMsDeathTimer(player.Id));
- despawnMysteriousStranger(player.Id);
- }
- void _MsIdle(Critter& ms)
- {
- // MS shall check if owner needs help.
- Critter@ player = GetCritter(ms.SpawnedBy);
- if (valid(player))
- {
- if (isCritterBelowHalfHp(player) && isMsFirstAidAvailable(player.Id))
- {
- ms.Say(SAY_NORM_ON_HEAD, "Look at that wound..");
- MS_LOG("MS Owner bellow half HP.");
- AddHealCritterPlane(ms, 100, player, true);
- setMsFirstAidAvailability(player.Id, false);
- }
- if (isCritterCrippled(player) && isMsDoctorAvailable(player.Id))
- {
- ms.Say(SAY_NORM_ON_HEAD, "It's first day at the clinic all over again.");
- MS_LOG("MS Owner is crippled.");
- AddDoctorCritterPlane(ms, 95, player, true);
- setMsDoctorAvailability(player.Id, false);
- }
- }
- }
- /**< */
- /**<
- * Combat aux.
- */
- bool isCritterCrippled(Critter& cr)
- {
- if (!valid(cr))
- return false;
- if (cr.IsDmgEye() || cr.IsDmgLeg() || cr.IsDmgArm())
- {
- return true;
- }
- else
- {
- return false;
- }
- }
- bool isCritterBelowHalfHp(Critter& cr)
- {
- if (!valid(cr))
- return false;
- if (cr.Stat[ST_CURRENT_HP] < 0.5 * cr.Stat[ST_MAX_LIFE])
- return true;
- else
- return false;
- }
- /**< */
- /**<
- * Player events for Player and related.
- * Added at map load, if the player has the MS_PERK. This might delete other events added to player, like logging.
- */
- void addMsSpawnEventsToPlayer(Critter& player)
- {
- MS_LOG("MS: Adding player attacked event.");
- player.SetEvent(CRITTER_EVENT_ATTACKED, "_PlayerMsAttacked");
- }
- void removeMsSpawnEventsFromPlayer(Critter& player)
- {
- MS_LOG("MS: Removing player attacked event.");
- player.SetEvent(CRITTER_EVENT_ATTACKED, "_PlayerMsAttacked_Removed");
- }
- bool _PlayerMsAttacked(Critter& player, Critter& attacker)
- {
- MS_LOG("MS: Player Attacked Event triggered.");
- if (!isMsSpawned(player.Id))
- {
- if (isCritterCrippled(player))
- {
- spawnMysteriousStrangerForDoctor(player.Id);
- Critter@ ms = GetCritter(getMsId(player.Id));
- if (valid(ms) && !ms.CheckEnemyInStack(attacker.Id))
- {
- MS_LOG("MS: (Spawned for Doctor) Adding attacker of owner to enemy stack.");
- ms.AddEnemyInStack(attacker.Id);
- AddAttackPlane(ms, 80, attacker, true);
- }
- }
- else if (isCritterBelowHalfHp(player))
- {
- spawnMysteriousStrangerForFirstAid(player.Id);
- Critter@ ms = GetCritter(getMsId(player.Id));
- if (valid(ms) && !ms.CheckEnemyInStack(attacker.Id))
- {
- MS_LOG("MS: Adding target of owner to enemy stack.");
- ms.AddEnemyInStack(attacker.Id);
- AddAttackPlane(ms, 80, attacker, true);
- }
- }
- }
- return true;
- }
- bool _PlayerMsAttacked_Removed(Critter& player, Critter& attacker)
- {
- MS_LOG("MS: Player Attacked Event is empty, because the map is not enabled for MS.");
- return true;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement