// Henchmen Always Bleed to Death // By Demtrious, OldManWhistler and IntrepidCW // // PLEASE READ "habd_include" FOR MORE INFORMATION. // // OnPlayerDying event handler. #include "habd_include" #include "subdual_inc" // **************************************************************************** // This function plays a random bleeding VoiceChat on a player. // oPC - the player to make play a bleed voice. void PlayBleedVoice (object oPC); void PlayBleedVoice (object oPC) { int iplay = FALSE; //PlayingVoices activated? if ( HABD_PLAY_BLEED_VOICE ==TRUE && HABD_PLAY_BLEED_VOICE<2) iplay = TRUE; if ( HABD_PLAY_BLEED_VOICE >1 && HABD_PLAY_BLEED_VOICE<=100 ) if ( d100(1) >= HABD_PLAY_BLEED_VOICE ) iplay = TRUE; if (iplay == TRUE) switch (d6()) { case 1: PlayVoiceChat (VOICE_CHAT_PAIN1, oPC); break; case 2: PlayVoiceChat (VOICE_CHAT_PAIN2, oPC); break; case 3: PlayVoiceChat (VOICE_CHAT_PAIN3, oPC); break; case 4: PlayVoiceChat (VOICE_CHAT_HEALME, oPC); break; case 5: PlayVoiceChat (VOICE_CHAT_NEARDEATH, oPC); break; case 6: PlayVoiceChat (VOICE_CHAT_HELP, oPC); break; } return; } // **************************************************************************** // Returns the delay in seconds that must be applied to the player healing // after estabilization. float DelayToHeal(object oPC); float DelayToHeal(object oPC) { float ftime = 1.0; if (HABD_DELAY_TOHEAL == 0.0 || GetCurrentHitPoints(oPC)>=1) ftime = 1.0; //the old HABD value else { ftime = HABD_DELAY_TOHEAL * IntToFloat(1- GetCurrentHitPoints(oPC) ); if (ftime < 1.0) ftime = 1.0; } return ftime; } // **************************************************************************** // Heals players to 1 hp and to removes negative effects. In also calls the // user defined bleed stabilization function. // oPC - the player to heal. void HealTo1HP(object oPC, int iIgnoreDelayVar = FALSE); void HealTo1HP(object oPC, int iIgnoreDelayVar = FALSE) { object oMod = GetModule(); string sID = GetPCPlayerName(oPC)+GetName(oPC); if (GetLocalInt(oMod, HABD_DELAYTOHEAL_CONTROL+sID) == FALSE & iIgnoreDelayVar == FALSE) return; DeleteLocalInt(oMod, HABD_DELAYTOHEAL_CONTROL+sID); // If player is already alive then abort. if (HABDGetHABD_PLAYER_STATE(sID, oPC) == HABD_STATE_PLAYER_ALIVE) return; int iNPC = GetLocalInt(OBJECT_SELF, HABD_NPC_BLEED); // Give the player a chance to run away if (HABD_POST_BLEED_INVIS_DUR > 0.0) ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectInvisibility(INVISIBILITY_TYPE_NORMAL), oPC, HABD_POST_BLEED_INVIS_DUR); if (HABD_POST_BLEED_CONCEAL_DUR > 0.0 && HABD_POST_BLEED_INVIS_DUR > 0.0) if (HABD_POST_BLEED_CONCEAL_DUR >= HABD_POST_BLEED_INVIS_DUR ) ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectConcealment(100,MISS_CHANCE_TYPE_NORMAL), oPC, HABD_POST_BLEED_INVIS_DUR); if (HABD_POST_BLEED_INVIS_DUR > HABD_POST_BLEED_CONCEAL_DUR ) ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectConcealment(100,MISS_CHANCE_TYPE_NORMAL), oPC, HABD_POST_BLEED_CONCEAL_DUR); // Turn the plot flag off after a specific period of time. SetPlotFlag(oPC, FALSE); // Raises the player to 1 hp. ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectHeal(1 - (GetCurrentHitPoints(oPC))), oPC); HABDSetHABD_PLAYER_STATE(HABD_STATE_PLAYER_ALIVE, sID, oPC); //set player state to alive // If this is a henchmen, then take them out of the busy state. if (iNPC) { HABDAssociateNotBusy(); } // Keep the player from being attacked, stop nearby attackers AssignCommand(oPC, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectInvisibility(INVISIBILITY_TYPE_NORMAL), oPC, 6.0)); // Make the player hostile again. SetStandardFactionReputation(STANDARD_FACTION_HOSTILE, GetLocalInt(oPC, HABD_OLD_FACTION), oPC); DeleteLocalInt(oPC, HABD_OLD_FACTION_SET); AssignCommand(oPC, ActionPlayAnimation(ANIMATION_LOOPING_PAUSE_DRUNK, 1.0, 5.0)); // Notify the player that they were healed. DelayCommand(0.5, SendMessageToPC(oPC, "You have healed.")); // Apply user defined penalties. AssignCommand(oPC, HABDUserDefinedBleed()); //Give a little visual effect for flare. effect eVisual = EffectVisualEffect(VFX_IMP_RESTORATION); ApplyEffectToObject(DURATION_TYPE_INSTANT, eVisual, oPC); // If regeneration items were removed then reequip them. if (HABD_NERF_REGENERATION_ITEMS) { AssignCommand(oPC, HABDRegenerationItemsReEquip(oPC)); } //Save info to DB (and maybe export PC) to avoid server crash problems, //now that we are sure the PC is Alive. if ( HABD_SMART_SAVETODB == TRUE ) HABDSetDBString(oPC); // Fixes the inital respawn issue with monsters not reattacking. //object oMonster = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oPC, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN); //DelayCommand(9.0, AssignCommand(oMonster, ActionAttack(oPC))); } // **************************************************************************** // Returns TRUE if the player has stabilized by gaining any HP since the last // time they bled. int CheckForStabilization(object oPC); int CheckForStabilization(object oPC) { object oMod = GetModule(); string sID = GetPCPlayerName(oPC)+GetName(oPC); //Section deals with possibility for healing by other players int lastHP = 0; if (GetIsPC(oPC) && GetIsDMPossessed(oPC) == FALSE)//PC lastHP = GetLocalInt(oMod, HABD_LAST_HP+sID); else //NPC lastHP = GetLocalInt(oPC, HABD_LAST_HP); if (GetCurrentHitPoints(oPC) > lastHP) //if hitpoint have increased { float ftime = DelayToHeal(oPC); DelayCommand(ftime, HealTo1HP(oPC)); if (FloatToInt(ftime)>1) { if(HABD_USERLANGUAGE==0) FloatingTextStringOnCreature(GetName(oPC)+" will heal to 1 HP in: "+IntToString(FloatToInt(ftime))+" seconds.", oPC, TRUE); else if (HABD_USERLANGUAGE==1) FloatingTextStringOnCreature(GetName(oPC)+" se curara a 1 PG en: "+IntToString(FloatToInt(ftime))+" segundos.", oPC, TRUE); } SetLocalInt(oMod, HABD_DELAYTOHEAL_CONTROL+sID, TRUE); return TRUE; } return FALSE; } // **************************************************************************** // Report the bleed count for OBJECT_SELF. void ReportPlayerBleed(); void ReportPlayerBleed() { object oPC = OBJECT_SELF; object oMod = GetModule(); string sID = GetPCPlayerName(oPC)+GetName(oPC); int iHPs = GetCurrentHitPoints(oPC); int iNPC = GetLocalInt(OBJECT_SELF, HABD_NPC_BLEED); if (iNPC) iHPs = iHPs - 10; if ( (HABDGetHABD_PLAYER_STATE(sID, oPC) != HABD_STATE_PLAYER_BLEEDING) || // check if player is still bleeding (iHPs > 0) || // player has healed (iHPs <= -10) || // player is a goner, let the death script kick in (CheckForStabilization(oPC)) // check if player has gained any HP ) { DeleteLocalInt(oPC, HABD_REPORT_BLEED_RUNNING); return; } // The delay will effect how often players are vocal about bleeding. DelayCommand(6.0, AssignCommand(oPC, ReportPlayerBleed())); // Prevent calling this function multiple times SetLocalInt(oPC, HABD_REPORT_BLEED_RUNNING, 1); string sbleedmsg = GetName(oPC)+" is bleeding to death! At "+IntToString(iHPs)+" hitpoints."; if(HABD_USERLANGUAGE==0) sbleedmsg = GetName(oPC)+" is bleeding to death! At "+IntToString(iHPs)+" hitpoints."; else if(HABD_USERLANGUAGE==1) sbleedmsg = GetName(oPC)+" esta muriendose! A "+IntToString(iHPs)+" puntos de golpe."; DelayCommand(0.1, FloatingTextStringOnCreature(sbleedmsg, oPC)); if (HABD_DM_NOTIFICATION_ON_BLEED) SendMessageToAllDMs(sbleedmsg); PlayBleedVoice(oPC); AssignCommand(oPC, ActionPlayAnimation(ANIMATION_LOOPING_DEAD_BACK, 1.0, 6.0)); } // **************************************************************************** // This function exists to fix the problem that occurs in bleeding scripts // when the summoned familiar is being possessed by the player (sorc or wiz). // That creates a condition where GetIsPC returns true for the familiar. // What usually happens is that when the possessed familiar dies, the player // is trapped in its body until the DM manually kills the player. // While stuck in the dead familiar, the player is unable to run the unpossess // action and the bleed count on the familiar usually does not work properly. // Whistler didnt take in mind that a player can possess the familiar even // when he is bleeding!!! it ruins all the timers. I havent found a fix that // doesnt kill the pet. // This function DOES NOT kill the familiar when the player is bleeding if the player // is not possessing the familiar. The familiar will be able to continue fighting // for its unconcious and bleeding master. // 1.65 has changed the familiar functions, but none of them seems to affect us // oTarget - the possibly "possessed" player. int KillPet(object oTarget, int nEffect = TRUE, int nVisualEffectId = VFX_IMP_UNSUMMON); int KillPet(object oTarget, int nEffect = TRUE, int nVisualEffectId = VFX_IMP_UNSUMMON) { // Usage: place in your bleeding script with a call that looks something like // if (KillPet(oPC)) return; // abort from the bleed script, oPC no longer exists effect eDeath = EffectDeath(FALSE, FALSE); effect eVis = EffectVisualEffect(nVisualEffectId); object oCreature = oTarget; if(GetIsObjectValid(oCreature)) { object oMaster = GetMaster(oCreature); if(GetIsObjectValid(oMaster)) { //Is the creature a summoned associate if(GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oMaster) == oCreature) { //Apply the VFX and delay the destruction of the summoned monster so //that the script and VFX can play. if(nEffect) DelayCommand(0.001,ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY,eVis,GetLocation(oCreature),1.0f)); SetPlotFlag(oCreature, FALSE); string skillpetmessage = GetName(oMaster)+" HAS LOST FAMILIAR '"+GetName(oCreature)+"'"; if(HABD_USERLANGUAGE==0) skillpetmessage = GetName(oMaster)+" HAS LOST FAMILIAR '"+GetName(oCreature)+"'"; else if(HABD_USERLANGUAGE==1) skillpetmessage = GetName(oMaster)+" HA PERDIDO SU FAMILIAR '"+GetName(oCreature)+"'"; DelayCommand(0.002,FloatingTextStringOnCreature(skillpetmessage, oCreature)); if (HABD_DM_NOTIFICATION_ON_BLEED) SendMessageToAllDMs(skillpetmessage); DelayCommand(0.003, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eDeath, oCreature)); return TRUE; } } } return FALSE; } // **************************************************************************** // It will kill any familiar of the PC. Take in mind that a player can possess // the familiar even when he is bleeding!!! it ruins all the timers. I havent // found a fix that doesnt kill the pet. // Facts: if you are alone in the server and posses a familiar, GetFirstPC() // doesnt seem to return something that is not usefull. void DestroyFamiliar(object oPC); void DestroyFamiliar(object oPC) { int i = 1; object oPet = GetAssociate(ASSOCIATE_TYPE_FAMILIAR,oPC,i); effect eDeath = EffectDeath(FALSE, FALSE); while( oPet != OBJECT_INVALID ) { if(HABD_USERLANGUAGE==0) SendMessageToPC(oPC, "HABD: Your familiar died"); else if(HABD_USERLANGUAGE==1) SendMessageToPC(oPC, "HABD: Tu familiar ha muerto"); ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eDeath, oPet); i=i+1; oPet = GetAssociate(ASSOCIATE_TYPE_FAMILIAR,oPC,i); } } // **************************************************************************** // Applies -1 HP to the player and checks for stabilization. // fBleedTimer - the time duration between bleeding -1 HP. void BleedToDeath(float fBleedTimer, object oPC, int iCoupDeGrace, object oFamiliar = OBJECT_INVALID) { object oMod = GetModule(); //object oPC = OBJECT_SELF; // whistler: if this is a player in a possessed familiar, then just kill it. // IntrepidCW: However, calling it in the BleedToDeath function will ruin the // bleeding chain. So we also restore the bleeding chain // Known Bug: If the plater possess the familiar when he has stabilized // but the 1 HP healing has not still been applied, he will remain at ground // (logout/login could solve the problem) if (HABD_FAMILIAR_EXPLOIT <=1) if ( GetIsPC(oFamiliar) || GetIsPossessedFamiliar(oFamiliar) ) { KillPet(oFamiliar); AssignCommand(oMod, DelayCommand(fBleedTimer, BleedToDeath(fBleedTimer, oPC, iCoupDeGrace, OBJECT_INVALID ))); return; } string sID = GetPCPlayerName(oPC)+GetName(oPC); int iNPC = GetLocalInt(OBJECT_SELF, HABD_NPC_BLEED); if (HABD_DEBUG) SpeakString("DEBUG: HABD OnBleed, "+GetName(oPC)+", HP: "+IntToString(GetCurrentHitPoints(oPC))+", master: "+GetName(GetMaster(oPC))+", state:"+HABDGetPlayerStateName(oPC), TALKVOLUME_SHOUT); //DEBUG: Not translated to spanish int iPlayerState = HABDGetHABD_PLAYER_STATE(sID, oPC); if (iPlayerState != HABD_STATE_PLAYER_BLEEDING) return; // Deals with a exploit that happens when you level up while bleeding if ( GetLocalInt(oPC, HABD_LAST_LEVEL) != 0 ) { if ( GetHitDice(oPC) > GetLocalInt(oPC, HABD_LAST_LEVEL) ) { SetLocalInt(oPC, HABD_LAST_LEVEL, GetHitDice(oPC) ); //Kill the PC if ( HABD_LEVELUPBLEED_EXPLOIT_KILLS == TRUE ) { if(HABD_USERLANGUAGE==0) { SendMessageToPC(oPC,"You have died, because you used the exploit to level up when Bleeding. If error, alert DMs with full details."); SendMessageToAllDMs(GetName(oPC)+" (Player:"+GetPCPlayerName(oPC)+" has died, because you used the exploit to level up when Bleeding."); } else if(HABD_USERLANGUAGE==1) { SendMessageToPC(oPC,"Has muerto, por que usaste la trampa de subir de nivel mientras morias. En caso de error, alerta a los DMs con detalles completos."); SendMessageToAllDMs(GetName(oPC)+" (El Jugador:"+GetPCPlayerName(oPC)+" ha muerto, por que uso la trampa de subir de nivel mientras moria."); } WriteTimestampedLogEntry(GetName(oPC)+" (Player:"+GetPCPlayerName(oPC)+") has died, because you used the exploit to level up when Bleeding."); // Ensure that plot is not still set. SetPlotFlag(oPC, FALSE); // Drop him to -10 HPs ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectDamage(GetCurrentHitPoints(oPC)+10,DAMAGE_TYPE_MAGICAL,DAMAGE_POWER_PLUS_FIVE), oPC); // Set up the hostile faction again. SetStandardFactionReputation(STANDARD_FACTION_HOSTILE, GetLocalInt(oPC, HABD_OLD_FACTION), oPC); DeleteLocalInt(oPC, HABD_OLD_FACTION_SET); // Set playerstate to dead not dying HABDSetHABD_PLAYER_STATE(HABD_STATE_PLAYER_DEAD, sID, oPC); // OnPlayerDead script will be called after this. // BleedToDeath will be called one more time, but it will instantly // abort because the player is not in the bleeding state. return; } else { if(HABD_USERLANGUAGE==0) { SendMessageToPC(oPC,"You used the exploit to level up when Bleeding, DMs will know it. If error, alert DMs with full details."); SendMessageToAllDMs(GetName(oPC)+" (Player:"+GetPCPlayerName(oPC)+" Used the exploit to level up when Bleeding."); } else if(HABD_USERLANGUAGE==1) { SendMessageToPC(oPC,"Has usado la trampa de subir de nivel mientras morias, los DMs han sido avisados y lo sabran leyendo el Log. En caso de error, alerta a los DMs con detalles completos."); SendMessageToAllDMs(GetName(oPC)+" (El Jugador:"+GetPCPlayerName(oPC)+" Uso la trampa de subir de nivel mientras moria."); } WriteTimestampedLogEntry(GetName(oPC)+" (Player:"+GetPCPlayerName(oPC)+" Used the exploit to level up when Bleeding."); } } //else SetLocalInt(oPC, HABD_LAST_LEVEL, GetHitDice(oPC) ); } else SetLocalInt(oPC, HABD_LAST_LEVEL, GetHitDice(oPC) ); // - end of antiexploit code //Coup de Grace for PCs alone in area feature if ( iCoupDeGrace == TRUE) if ( GetHitDice(oPC) > HABD_NO_DEATH_UNTIL_LEVEL ) if ( HABD_GetIsSafeArea(oPC) == FALSE) { //kill the PC if(HABD_USERLANGUAGE==0) SendMessageToPC(oPC,"You have died, due to coup of grace,"); else if(HABD_USERLANGUAGE==1) SendMessageToPC(oPC,"Has muerto, debido a un golpe de gracia,"); // Ensure that plot is not still set. SetPlotFlag(oPC, FALSE); // Drop him to -10 HPs ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectDamage(GetCurrentHitPoints(oPC)+10,DAMAGE_TYPE_MAGICAL,DAMAGE_POWER_PLUS_FIVE), oPC); // Set up the hostile faction again. SetStandardFactionReputation(STANDARD_FACTION_HOSTILE, GetLocalInt(oPC, HABD_OLD_FACTION), oPC); DeleteLocalInt(oPC, HABD_OLD_FACTION_SET); // Set playerstate to dead not dying HABDSetHABD_PLAYER_STATE(HABD_STATE_PLAYER_DEAD, sID, oPC); // OnPlayerDead script will be called after this. // BleedToDeath will be called one more time, but it will instantly // abort because the player is not in the bleeding state. return; } //- //Check if someone has healed at least one hp to the PC. if (CheckForStabilization(oPC)) return; // if you get here - you are dying and have not been healed // so you need to roll to see if you stabilize. Default d10. int nSavingRoll = Random(HABD_STABILIZATION_DICE)+1; // See what you must roll to self-stabilized int iNeededSavingRoll = HABD_GLOBAL_STABILIZATION_NUMBER; if ( HABDPlayerIsSolo(oPC) ) iNeededSavingRoll = HABD_SOLO_STABILIZATION_NUMBER; // Death can be disabled before a certain level by "faking" the stabilization // check. Do not let the players know that death is disabled because it will // only encourage them to be idiots. if ((HABD_NO_DEATH_UNTIL_LEVEL) && (GetHitDice(oPC) < HABD_NO_DEATH_UNTIL_LEVEL)) { switch (GetCurrentHitPoints(oPC)) { case 10: case -1: nSavingRoll = nSavingRoll + 2*HABD_STABILIZATION_DICE/10; break; case 9: case -2: nSavingRoll = nSavingRoll + 3*HABD_STABILIZATION_DICE/10; break; case 8: case -3: nSavingRoll = nSavingRoll + 4*HABD_STABILIZATION_DICE/10; break; case 7: case -4: nSavingRoll = nSavingRoll + 5*HABD_STABILIZATION_DICE/10; break; case 6: case -5: nSavingRoll = nSavingRoll + 6*HABD_STABILIZATION_DICE/10; break; case 5: case -6: nSavingRoll = nSavingRoll + 7*HABD_STABILIZATION_DICE/10; break; case 4: case -7: nSavingRoll = nSavingRoll + 8*HABD_STABILIZATION_DICE/10; break; case 3: case -8: nSavingRoll = nSavingRoll + 9*HABD_STABILIZATION_DICE/10; break; case 2: case -9: default: nSavingRoll = nSavingRoll + HABD_STABILIZATION_DICE; break; } } //Default 10 for 3E - lower for easier stabilization int iStabilized = FALSE; if (nSavingRoll >= iNeededSavingRoll) iStabilized = TRUE; else if (HABD_GetIsSafeArea(oPC) == TRUE) iStabilized = TRUE; //Stabilized if (iStabilized == TRUE) { float ftime = DelayToHeal(oPC); DelayCommand(ftime, HealTo1HP(oPC)); //call heal subroutine if (FloatToInt(ftime)>1) { if(HABD_USERLANGUAGE==0) FloatingTextStringOnCreature(GetName(oPC)+" will heal to 1 HP in: "+IntToString(FloatToInt(ftime))+" seconds.", oPC, TRUE); else if(HABD_USERLANGUAGE==1) FloatingTextStringOnCreature(GetName(oPC)+" se curara a 1 PG en: "+IntToString(FloatToInt(ftime))+" segundos.", oPC, TRUE); } SetLocalInt(GetModule(), HABD_DELAYTOHEAL_CONTROL+sID, TRUE); // Always make it look like they rolled a 10 to stabilize if(HABD_USERLANGUAGE==0) { SendMessageToPC(oPC,"Saving Roll to stop bleeding (at "+IntToString(GetCurrentHitPoints(oPC))+") = 10"); FloatingTextStringOnCreature(GetName(oPC)+" has self-stabilized.", oPC); DelayCommand(6.0, SendMessageToPC(oPC, "In a life or death effort you have survived, alive but barely.")); } else if(HABD_USERLANGUAGE==1) { SendMessageToPC(oPC,"Tirada de Estabilizacion (a "+IntToString(GetCurrentHitPoints(oPC))+") = 10"); FloatingTextStringOnCreature(GetName(oPC)+" se ha auto-estabilizado.", oPC); DelayCommand(6.0, SendMessageToPC(oPC, "En un esfuerzo a vida o muerte has sobrevivido, vivo pero herido.")); } return; } //if you get here, you have not been healed and did not successfully stabilize else { // Most important, keep the bleeding chain going. AssignCommand(oMod, DelayCommand(fBleedTimer, BleedToDeath(fBleedTimer, oPC, iCoupDeGrace, oFamiliar))); if(HABD_USERLANGUAGE==0) SendMessageToPC(oPC,"Saving Roll to stop bleeding (at "+IntToString(GetCurrentHitPoints(oPC))+") = " +IntToString(nSavingRoll)); else if(HABD_USERLANGUAGE==1) SendMessageToPC(oPC,"Tirada de Estabilizacion (a "+IntToString(GetCurrentHitPoints(oPC))+") = " +IntToString(nSavingRoll)); SetPlotFlag(oPC, FALSE); ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectDamage(1,DAMAGE_TYPE_MAGICAL,DAMAGE_POWER_PLUS_FIVE), oPC); SetPlotFlag(oPC, TRUE); // Update local variable with hitpoints for healing option. if (GetIsPC(oPC) && GetIsDMPossessed(oPC) == FALSE) //PC SetLocalInt(oMod,HABD_LAST_HP+sID, GetCurrentHitPoints(oPC)); else //NPC SetLocalInt(oPC,HABD_LAST_HP, GetCurrentHitPoints(oPC)); // if this is true then the player has died. if (GetCurrentHitPoints(oPC) <= -10) { if(HABD_USERLANGUAGE==0) SendMessageToPC(oPC,"You have died."); else if(HABD_USERLANGUAGE==1) SendMessageToPC(oPC,"Has muerto."); // Ensure that plot is not still set. SetPlotFlag(oPC, FALSE); // Set up the hostile faction again. SetStandardFactionReputation(STANDARD_FACTION_HOSTILE, GetLocalInt(oPC, HABD_OLD_FACTION), oPC); DeleteLocalInt(oPC, HABD_OLD_FACTION_SET); // Set playerstate to dead not dying HABDSetHABD_PLAYER_STATE(HABD_STATE_PLAYER_DEAD, sID, oPC); // OnPlayerDead script will be called after this. // BleedToDeath will be called one more time, but it will instantly // abort because the player is not in the bleeding state. return; } } } // **************************************************************************** // OnPlayerDying event handler. void main() { if (CheckSubdual(GetLastPlayerDying())) return; { object oMod = GetModule(); object oPC = GetLastPlayerDying(); int iNPC = GetLocalInt(OBJECT_SELF, HABD_NPC_BLEED); if (iNPC == 1) oPC = OBJECT_SELF; string sID = GetPCPlayerName(oPC)+GetName(oPC); //to properly deal with the levelling up while bleeding exploit. SetLocalInt(oPC, HABD_LAST_LEVEL, GetHitDice(oPC) ); // If an NPC is running this script, then set up its master. The master was // automatically wiped out when the henchman died. if (iNPC) { if (!GetIsObjectValid(GetAssociate(ASSOCIATE_TYPE_HENCHMAN, GetLocalObject(OBJECT_SELF, HABD_NPC_MASTER)))) AddHenchman(GetLocalObject(OBJECT_SELF, HABD_NPC_MASTER), oPC); //if HABD bleeding is disabled for Henchmen if ( HABD_HENCHMEN_BLEED == FALSE || HABD_HENCHMEN_BLEED == 2 ) return; } //DEBUG: Not translated to Spanish if (HABD_DEBUG) SpeakString("DEBUG: HABD OnDying, "+GetName(oPC)+", HP: "+IntToString(GetCurrentHitPoints(oPC))+", master: "+GetName(GetMaster(oPC))+", state:"+HABDGetPlayerStateName(oPC), TALKVOLUME_SHOUT); // Check if bleeding is running on DM or DM possessed, then abort. if(GetIsDM(oPC) || GetIsDM(GetMaster(oPC))) return; // whistler: if this is a player in a possessed familiar, then just kill it. // Familiar penalties will kick in when familiar dies. if (KillPet(oPC)) return; // Intrepid: Damn, player can possess a familiar when they are bleeding, which // ruins all the bleeding thing (at least in NWN 1.64 patch). The only fix // 100% relliable I have now is to kill all familiars. if (HABD_FAMILIAR_EXPLOIT == 0) DestroyFamiliar(oPC); int iState = HABDGetHABD_PLAYER_STATE(sID, oPC); if ((iState == HABD_STATE_PLAYER_DEAD) || (iState == HABD_STATE_RESPAWNED_GHOST)) return; if ( iState == HABD_STATE_PC_PERMADEATH ) { ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectHeal(1 - (GetCurrentHitPoints(oPC))), oPC); HABDJumpToPermaDeathPoint(oPC, HABD_EVENTDYINGSIGNAL); return; } //coup de grace feature int CoupDeGrace = HABDCoupDeGraceAloneInArea(oPC); // Most important, issue the commands to start the bleeding chain. float fBleedTimer = HABDGetBleedTimer(oPC); //start the bleeding chain AssignCommand(oMod, DelayCommand(fBleedTimer, BleedToDeath(fBleedTimer, oPC, CoupDeGrace, GetAssociate(ASSOCIATE_TYPE_FAMILIAR,oPC,1) ))); if (GetLocalInt(oPC, HABD_REPORT_BLEED_RUNNING) == 0) DelayCommand(6.0, AssignCommand(oPC, ReportPlayerBleed())); int iHPs = GetCurrentHitPoints(oPC); SetPlotFlag(oPC, TRUE); // Force friendly to hostile faction. if (!GetLocalInt(oPC, HABD_OLD_FACTION_SET)) { SetLocalInt(oPC, HABD_OLD_FACTION, GetStandardFactionReputation(STANDARD_FACTION_HOSTILE, oPC)); SetLocalInt(oPC, HABD_OLD_FACTION_SET, 1); } SetStandardFactionReputation(STANDARD_FACTION_HOSTILE, 100, oPC); // Keep the player from being attacked, stop nearby attackers HABDStopNearbyAttackers(oPC); // CAP TO NEGATIVE HPs // Allow a good chance for healing - will limit HP to -5 on a bleed level hit. // Actually configurable via constant HABD_BLEEDING_START_LIMIT if ( HABD_BLEEDING_START_LIMIT > -10) if ( HABD_GetIsHardArea(oPC) == FALSE) if ( (iHPs < HABD_BLEEDING_START_LIMIT) && (iState == HABD_STATE_PLAYER_ALIVE) ) { //should heal player to -5 (if default) int nHeal = HABD_BLEEDING_START_LIMIT - iHPs; ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectHeal(nHeal), oPC); } // Set the state variables. iHPs = GetCurrentHitPoints(oPC); HABDSetHABD_PLAYER_STATE(HABD_STATE_PLAYER_BLEEDING, sID, oPC); if (GetIsPC(oPC) && GetIsDMPossessed(oPC) == FALSE) //PC SetLocalInt(oMod,HABD_LAST_HP+sID, GetCurrentHitPoints(oPC)); else //NPC SetLocalInt(oPC,HABD_LAST_HP, GetCurrentHitPoints(oPC)); // Check if we are re-entering this state from persistence. if (GetLocalInt(oPC, HABD_PERSISTANT_REAPPLY) != 1) { // Increment the counters. SetLocalInt(oMod, HABD_CURRENT_BLEED_COUNT+sID, GetLocalInt(oMod, HABD_CURRENT_BLEED_COUNT+sID) + 1); SetLocalInt(oMod, HABD_BLEED_COUNT+sID, GetLocalInt(oMod, HABD_BLEED_COUNT+sID) + 1); } else { DeleteLocalInt(oPC, HABD_PERSISTANT_REAPPLY); } // Nerf regeneration items. if (HABD_NERF_REGENERATION_ITEMS) { AssignCommand(oPC, HABDRegenerationItemsUnequip(oPC)); } // Notify that bleeding has started. if (iNPC) iHPs = iHPs - 10; string sMsg = GetName(oPC)+" is bleeding to death! At "+IntToString(iHPs)+" hitpoints. Will die in "+FloatToString((10 + iHPs)*fBleedTimer, 3, 0)+" seconds."; if(HABD_USERLANGUAGE==0) sMsg = GetName(oPC)+" is bleeding to death! At "+IntToString(iHPs)+" hitpoints. Will die in "+FloatToString((10 + iHPs)*fBleedTimer, 3, 0)+" seconds."; else if(HABD_USERLANGUAGE==1) sMsg = GetName(oPC)+" esta muriendose! A "+IntToString(iHPs)+" puntos de golpe. Morira en "+FloatToString((10 + iHPs)*fBleedTimer, 3, 0)+" segundos."; if (HABD_DM_NOTIFICATION_ON_BLEED) SendMessageToAllDMs(sMsg); FloatingTextStringOnCreature(sMsg, oPC); //Save info to DB (and maybe export PC) to avoid server crash problems, //now that we are sure the PC is bleeding. if ( HABD_SMART_SAVETODB == TRUE ) HABDSetDBString(oPC); } }