Aller au contenu

Photo

Hiring Companions for a duration


  • Veuillez vous connecter pour répondre
19 réponses à ce sujet

#1
Fyrekrest

Fyrekrest
  • Members
  • 22 messages
I was wondering if anyone would be able to help me with what I hope is a simple script.  Unfortunately, scripting is very difficult for me to understand, so I rely a lot on google, the vault and these forums to provide the scripts that I need.  Unfortunately, I cannot find one that emulates what I am trying to do.  I am trying to create a system of companions for a PW I am developing for myself and some friends in which the players may hire up to 2 henchmen each (within a maximum limit of 6 characters per party), but each henchman is paid for a specific duration, at which time they either provide the option to hire again and stay with the player, or return to their original location.  Unfortunately, I can find very little information in regards to henchmen on a PW nor hiring for a timed duration (one hour).  Any help would be greatly appreciated, even if it is simply to nudge me in the right direction to find my answers!

Thanks!:happy:

#2
Morbane

Morbane
  • Members
  • 1 883 messages
You might have some luck searching the Lexicon for Time related functions - like GetTimeHour()

hire hench on GetTimeHour()
release hench on GetTime Hour() +1

#3
MasterChanger

MasterChanger
  • Members
  • 686 messages
There are a number of approaches; it's really a question of which one will function most reliably and efficiently for your needs.

My first suggestion would be to think about using DelayCommand to call your hire-or-release script in an hour (probably not while in combat--eep!). I don't know if DelayCommand will work if the player leaves and re-joins the server, however...will the countdown resume when they rejoin?

You could also start a timer with NWNX, which is generally a reliable way to go about things. Again, I don't know what happens if a PC leaves and rejoins.

Of course, you could also run a heartbeat on the NPC. This would certainly work whenever the PC and NPC are present, but a lot of PCs with a lot of henchmen all running extra checks in their heartbeats might be a performance hit (though I'd imagine it would be relatively minor).

Pain could probably tell you. He's done tons of PW scripting.

#4
Shallina

Shallina
  • Members
  • 1 011 messages
I'd use Morbane approach.

#5
MasterChanger

MasterChanger
  • Members
  • 686 messages

Shallina wrote...

I'd use Morbane approach.


Morbane's approach just gets the time. That's fine, but what event would you call it from? Heartbeat of the module, hench, etc.?

#6
kamal_

kamal_
  • Members
  • 5 250 messages

MasterChanger wrote...

Shallina wrote...

I'd use Morbane approach.


Morbane's approach just gets the time. That's fine, but what event would you call it from? Heartbeat of the module, hench, etc.?

Hench heartbeat. It will make the scripting of things like detecting if the hench is in combat much simpler. Performance won't be a problem either since the henchies are already running heartbeats anyway.

#7
PJ156

PJ156
  • Members
  • 2 983 messages
I'm no scripter myself but for this I would try to put an integer on the henchman.

On each heartbeat (6 secs) add one and then test its value. If it is less than 600 then continue, if it is greater than 600 but not in combat then start the convo. That makes it independant of the actual time and I think Lilac soul could write that one for you.

PJ

Modifié par PJ156, 19 novembre 2011 - 11:27 .


#8
Shallina

Shallina
  • Members
  • 1 011 messages
Get the time then check the time in an heartbat and see if you are still in time.

#9
Lugaid of the Red Stripes

Lugaid of the Red Stripes
  • Members
  • 955 messages
I would use the henchman's heartbeat. When the henchmen is hired, first set a boolean that says they're a temporary hire. Then set an integer that represents the number of rounds their term of service lasts (since you have one heartbeat every round). One hour, then, would be 600 (3600 seconds/6 seconds). A third variable, your counter, would be set to 0.

On every heartbeat, the script checks to see if the henchmen is a temp hire (your boolean), and then adds one to your counter. If the counter is greater than the term of service, the script orders the henchmen to start a conversation with the PC. If either the henchmen or the PC are in combat, the conversation fails to fire and the script will try again on the next heartbeat. You might even want to keep track of the extra rounds, so the henchmen can demand a bonus before signing on again.

#10
Shallina

Shallina
  • Members
  • 1 011 messages
When a script is stoped, a creature moved and so on, when the player switch area or module, some action can be canceled such a DelayCommand.

So in order to have something working all the time, you need to store a value and check it, and compare so even if the script is interupted, when it will start again it should start from where it was stoped.

#11
kevL

kevL
  • Members
  • 4 061 messages
gonna throw some nutmeg in. To get away from heartbeat scripts, the convo-on-hiring could ( somehow ) set the current time as a global_var per the henchman's FirstName. Then place triggers in several ideal areas: if the time for that hench is >1hr the "Hey, I think it's time to talk wages" convo pops up (perhaps using the OnClientEnter script of each area). Add salt,

#12
Fyrekrest

Fyrekrest
  • Members
  • 22 messages
Thanks for the suggestions! I'm going to try starting with something simple using Lilac's and see what I can come up with (that works. Haha!). Again, I really appreciate the great suggestions!

#13
Shaughn78

Shaughn78
  • Members
  • 637 messages
How many henchman are you looking at having?

If you have having a number of henchmen it might make sense to add to the module heartbeat and cycle through the henchmen oppose to having each henchman fire off their script.

A few people have also mentioned checking if the PC and henchman are in combat, you may also want to check if the PC is already in a conversation.

I like the idea of counting the rounds that a the NPC & PC are busy. It would make sense that a hired sword may ask for more gold if their time ran out right before an epic battle.

#14
Fyrekrest

Fyrekrest
  • Members
  • 22 messages
Wow, I'm having a heck of a time with this! As it's my first real attempt with scripting, I'm not overly surprised, though! I would definitely appreciate a bit of insight into my problem....

I've started with a generic script to test things out, and I figure I'll customize it a bit more to each henchmen as I go. Right now, it works like this: PC speaks to NPC and can hire Henchman. Upon hire, Henchman spawns next to PC and I've attached all the default Companion scripts to the Henchman. I've added to the default gb_comp_heart script (heartbeat script) the following line:

ExecuteScript("psy_hench_hb1", OBJECT_SELF);

I've tried two different versions of psy_hench_hb1, but neither of them seem to work. The first was this:

int nInt;
/* Script generated by
Lilac Soul's NWN Script Generator, v. 2.3

For download info, please visit:
http://nwvault.ign.c...&id=4683&id=625 */

//Goes on creature's OnHeartbeat. Fires when not fighting or talking.
void main()
{

object oPC = GetNearestCreature(CREATURE_TYPE_PLAYER_CHAR, PLAYER_CHAR_IS_PC, OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN);

if (IsInConversation(OBJECT_SELF) || GetIsInCombat()) return;

if (GetLocalInt(oPC, "hench_timer")< 10)
{
nInt = GetLocalInt(oPC, "hench_timer");

nInt += 1;

SetLocalInt(oPC, "hench_timer", nInt);

}
if (GetLocalInt(oPC, "hench_timer")>= 10)
{
ActionStartConversation(oPC, "cnv_hench_rehire");

}
}

For the second attempt, I included setting the initial integer with the hiring conversation (hench_timer set to 1), added a second script to execute (psy_hench_hb2, along with psy_hench_hb1 in the default heartbeat script) and then tried this:

psy_hench_hb1:
/* Script generated by
Lilac Soul's NWN Script Generator, v. 2.3

For download info, please visit:
http://nwvault.ign.c...&id=4683&id=625 */

//Goes on creature's OnHeartbeat. Fires when not fighting or talking.
void main()
{

object oPC = GetNearestCreature(CREATURE_TYPE_PLAYER_CHAR, PLAYER_CHAR_IS_PC, OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN);

if (IsInConversation(OBJECT_SELF) || GetIsInCombat()) return;

int nInt;
nInt = GetLocalInt(oPC, "hench_timer");

nInt += 1;

SetLocalInt(oPC, "hench_timer", nInt);

}

psy_hench_hb2:
/* Script generated by
Lilac Soul's NWN Script Generator, v. 2.3

For download info, please visit:
http://nwvault.ign.c...&id=4683&id=625 */

//Goes on creature's OnHeartbeat. Fires when not fighting or talking.
void main()
{

object oPC = GetNearestCreature(CREATURE_TYPE_PLAYER_CHAR, PLAYER_CHAR_IS_PC, OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN);

if (IsInConversation(OBJECT_SELF) || GetIsInCombat()) return;

if (GetLocalInt(oPC, "hench_timer")< 5)
return;

ActionStartConversation(oPC, "cnv_hench_rehire");

}

Oddly, with the first attempt, if I hired a second henchman along with the first, the rehire conversation would pop up (both would fire simultaneously, which I assume is the result of setting only a single variable that they both operated off of). Yet, if I have only a single henchman hired, no matter how long I wait (up to five minutes), the rehire conversation does not fire. Any thoughts or insight?

#15
Lugaid of the Red Stripes

Lugaid of the Red Stripes
  • Members
  • 955 messages
I think the GetNearestObject function is causing issues. It might be the "SEEN" set of parameters, it might be that it's having trouble distinguishing between the 'real' PC and the PC-controlled henchmen.

So, first, for a test (Just a test, Pain) replace that function with GetFirstPC(). Once that works, set the PC as a local object on the henchman, maybe from the conversation that hires the henchman. Also, I would keep the int on the henchman themself, so you can easily have multiple henchmen with different terms of service.

#16
rjshae

rjshae
  • Members
  • 4 491 messages
How likely is it that a henchman would keep such an accurate time? I'd be tempted to call the check code during a rest cycle. The motivation for the player then is to maximize mileage before resting, thereby stressing other resources. Also, it'd perhaps be more realistic for the NPC to ask for more pay during a safe period of rest.

#17
The Fred

The Fred
  • Members
  • 2 516 messages
I would imagine that a henchmen would be hired out for periods of days or more at a time, so it makes a certain amount of sense for it to be checked when resting (given that's the most significant passage of time by default). Personally, I've recently been working on a bunch of time-based functions, so I'd be tempted to use something related to that (e.g. check if a tenday has passed, etc). The only thing is what's going to happen if the henchman is stuck in the middle of a dungeon when he decides to leave your service, say?

#18
Morbane

Morbane
  • Members
  • 1 883 messages
I did some idle testing - ther GetTime*() functions dont really work for math purposes - at least not in the way I originally suggested - that said I am a fair scripter but not like Pain or Knightmare.

Making a heartbeat counter on the henchman based on the 6 second cycle might be more effective and you would need to have multiple functions available for different time intervals.

pseudo code:

object oHench = OBJECT_SELF;
object oPC = GetMaster() //requires an #include but no toolset at the moment

int nTime = GetLocalInt(oHench);

SetLocalInt(oHench, nTime)

if(GetLocalInt(oHench) > nTime * hours or minutes or days e.g. 10 = minute / 86400 = day
do something - convo or action

that is the basic idea and not such a bad place to start. if I can get onto my game pc I will do some testing and experimenting.

good luck

Modifié par Morbane, 14 décembre 2011 - 09:47 .


#19
Dann-J

Dann-J
  • Members
  • 3 161 messages
The module heartbeat script that updated the MotB date/time GUI on the toolbar has the following code:

//On Module Heartbeat script
#include "ginc_time"
void main()
{
 struct CHoursPassed rHP = CheckTime();
 int nNumModuleHoursPassed = rHP.nNumModuleHoursPassed;
 int nNumCampaignHoursPassed = rHP.nNumCampaignHoursPassed;
 
 if ((nNumModuleHoursPassed > 0) ||
  (nNumCampaignHoursPassed > 0))
 {
  UpdateClockForAllPlayers();
 }  
}

Perhaps you could set a local variable on the henchman using the nNumModuleHoursPassed / nNumCampaignHoursPassed structure value when hired, then give them a custom HB script that constantly checks whether the hours passed has surpassed their hire time (before running the default henchman HB at the end of the script). The first few warnings could just fire some floating text warning of the time limit approaching, eventually resulting in a conversation (if not in combat) that forces the matter once the deadline has gone past by more than a few hours.

#20
Dann-J

Dann-J
  • Members
  • 3 161 messages

DannJ wrote...

The module heartbeat script that updated the MotB date/time GUI on the toolbar has the following code:

//On Module Heartbeat script
#include "ginc_time"
void main()
{
 struct CHoursPassed rHP = CheckTime();
 int nNumModuleHoursPassed = rHP.nNumModuleHoursPassed;
 int nNumCampaignHoursPassed = rHP.nNumCampaignHoursPassed;
 
 if ((nNumModuleHoursPassed > 0) ||
  (nNumCampaignHoursPassed > 0))
 {
  UpdateClockForAllPlayers();
 }  
}
.



The nNumModuleHoursPassed / nNumCampaignHoursPassed structure value is interesting - it returns the whole numnber of hours that have passed since the last time the function returned a non-zero value. It returns zero for the first 19 rounds, then 1 for the 20th, then returns back to zero. If you advance the time by a certain number of hours, then the next round it returns that value (so sleep for 8 hours, it returns an 8).

The following companion heartbeat script uses the function (some assembly required). It assumes a normal module. If you're using a campaign module, then use rHP.nNumCampaignHoursPassed instead.

--

// gb_comp_hired_heart
// Hearbeat script for companion hired by the hour
// Set local variables on companion: HoursPayedFor (int) and Conversation (string)
#include "ginc_time"
void main()
{
struct CHoursPassed rHP = CheckTime();
int nNumModuleHoursPassed = rHP.nNumModuleHoursPassed;
int iHoursPayedFor = GetLocalInt(OBJECT_SELF, "HoursPayedFor");
int iHoursElapsed = GetLocalInt(OBJECT_SELF, "HoursElapsed");
if ( nNumModuleHoursPassed > 1)
 {
 iHoursElapsed = iHoursElapsed + nNumModuleHoursPassed;
 SetLocalInt(OBJECT_SELF, "HoursElapsed", iHoursElapsed); 
 }
if (iHoursElapsed >= iHoursPayedFor)
 {
 // Check if in combat, or PC incapacitated or in conversation with someone else. If not...
 string sConv = GetLocalString(OBJECT_SELF, "Conversation");
 AssignCommand(GetFirstPC(), ActionStartConversation(OBJECT_SELF,sConv, FALSE, FALSE, TRUE, FALSE));
 }
  
ExecuteScript("gb_comp_heart", OBJECT_SELF); 
}

Modifié par DannJ, 15 décembre 2011 - 10:19 .