Untold Tales of Tolkien Series - Developments Thread

I hear you … It is hard to know what to do sometimes. If it wasn’t for the fact that I know I have friends ready to play co-op mode (for which I am very thankful), then I think I may have considered going SP only, simply due to the extra time it takes ensuring everything works in a MP mode.

Probably easier said than done. :wink: Depending upon what you have done or allow to happen in your module will affect any edits a lot. E.g. I have a few puzzles that when I first did them, only the activator could access them. However, my players wanted me to make it so they could both see the puzzle. This added a few days work. :sweat_smile: And that was just one puzzle!

That all said, I hope you do manage to accomplish a co-op mode, as that is something my friend and I would consider playing together! :+1:

1 Like

I do play a lot of co-op myself and my background with mods for NWN starts with PWs for NWN1. I’m often tempted to have another go, but I’m older now and experience tells me to bide my time and wait for the right moment. Not interested in PWs, but a single/co-op module in a new setting is something I’m very interested in somewhere in the distant future :slight_smile:

Upgrading the series to co-op could be done, if I feel I can embrace the pain!

1 Like

Same here … Not as a PW, but definitely for a co-op.

Good to hear! Maybe that explains my aches and pains … as much as old age. :wink:

2 Likes

Unfortunately I have to head off to work, but some very satisfying progress this morning!


Entering a warm area trigger. Sets a local int “rest_warm” to 1.


Exiting a warm area trigger, sets “rest_warm” to 0.


As well as tagging food items with a local string “rest_food”, I have colour-coded all of their names so they are easier to identify as a resting ration.

Now I just need to tie the whole thing together in the mod script. I will need to loop through the whole party for a ration item and check for warmth bonuses and then apply the rest effect. Easy, huh? :open_mouth:

3 Likes

note that the official campaigns allow co-op on a basic level – MotB is more complicated since it needs to track a “SpiritEater” character.

The basics seem straightforward – keep journal synched, use GetFirstPC() properly, etc. Lance on the other hand achieved full featured co-op/ MP i believe

/note

2 Likes

@MERP_UK

Sabranic implemented food/water in the NWN2 Conclusion Campaign

i believe it’s open-source, but might be a bit fancy for what you’re looking for :)

3 Likes

Thanks, I’ll have a shot at making it work tomorrow. If I hadnt completely forgotten while loops again, Id have some certainty it will work :joy:

I’ll try it myself, then seek similar scripts to figure it out and then scream here for help!

1 Like

how i learned to stop worrying and love the while() loop

2 Likes

Correct … Right down to different players being able to control their own PCs, or take control of another player’s PCs if agreed. i.e. Not just the leader controlling companions.

3 Likes

This worked very well in testing with a party of companions and associates. Note that I made the assumption that no-sleep triggers are tagged “RestTrigger”, warmth triggers are tagged “rest_warm”, and the food items have their localint “rest_food” set to 1.

// Place on the module's OnPlayerRest event.

/* 26/07/21 Kev. Deliverance modifications.
	Desired results...
	1. Player can rest freely, as long as they are not in a restricted zone (see d1_resting_restrict)
	2. Any member of the party must possess a food item holding local var "rest_food"
	3. Food item to be destroyed upon rest event
	4. If resting creature is within a warmth trigger, apply well rested bonus: Full health/abilities restore, +1 fortitude until next rest.
	5. If not resting in a warmth trigger, restore 75% health, restore all abilities.
*/

/*	Travus 7/26/21 - Added code to check/remove one food item from the party when resting.
	If resting in a warmth zone, the paty will heal fully and get a Fortitude bonus.
	If resting outside a warmth zone, the party will heal only to 75% due the frigid weather.
	Assumes all no-sleep triggers are tagged "RestTrigger".
	Assumes all warmth triggers are tagged "rest_warm".
	Assumes the food items have their localint "rest_food" set to 1.		
*/

int TakeFood(object oPC)
{
	object oFM = GetFirstFactionMember(oPC, FALSE);
	object oItem;
	
	while (GetIsObjectValid(oFM))
	{
		oItem = GetFirstItemInInventory(oFM);
		
		while (GetIsObjectValid(oItem)) 	
		{
			if (GetLocalInt(oItem, "rest_food"))
			{
				DestroyObject(oItem);
				return TRUE;
			}
			oItem = GetNextItemInInventory(oFM);
		}
		oFM = GetNextFactionMember(oPC, FALSE);
	}
	
	return FALSE;
}

void ApplyEffectToParty(object oPC, int bWarm=FALSE)
{
	int n; 
	effect eEffect = MagicalEffect(EffectSavingThrowIncrease(SAVING_THROW_FORT, 1));  	
	object oFM = GetFirstFactionMember(oPC, FALSE);
	
	while (GetIsObjectValid(oFM))
	{
		if (bWarm) ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEffect, oFM);
		
		else 
		{
			n = GetMaxHitPoints(oFM) / 4;
			ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(n, DAMAGE_TYPE_COLD), oFM);
		}
			 
		oFM = GetNextFactionMember(oPC, FALSE);
	}		
}
		
void main()
{
	object oPC = GetLastPCRested();
	int nRestAllow = TRUE;
	int nWarm;	
	int nRestEvent = GetLastRestEventType();	
	object oTrig = GetNearestObjectByTag("RestTrigger", oPC);
	object oPers = GetFirstInPersistentObject(oTrig);

	while (GetIsObjectValid(oPers))
	{
		if (oPers == oPC) nRestAllow = FALSE;
		oPers = GetNextInPersistentObject(oTrig);
	}
	
	if (!nRestAllow && nRestEvent == REST_EVENTTYPE_REST_STARTED)
	{
		AssignCommand(oPC, ClearAllActions());
		FloatingTextStringOnCreature("<color=red>It would be extremely dangerous to rest here!", oPC, FALSE);
	}
	
	else if (GetIsResting(oPC) && nRestEvent == REST_EVENTTYPE_REST_STARTED)
	{
		if (!TakeFood(oPC)) 
		{
			AssignCommand(oPC, ClearAllActions());
			FloatingTextStringOnCreature("<color=yellow>You do not have enough food to rest!", oPC, FALSE);
		}

		else 
		{
			object oIP = CreateObject(OBJECT_TYPE_PLACEABLE, "plc_ipoint ", GetLocation(oPC));
										//	   do not remove this space ^
			string sYawn = "as_pl_snoringm1";
			string sWake = "as_pl_yawningm1";
	
			if (GetGender(oPC) == GENDER_FEMALE)
			{
				sYawn = "as_pl_snoringm1";
				sWake = "as_pl_yawningf1";
			}
			
			// Playsound does not work on the same object while it is animating. So play it off of an ipoint.
			DelayCommand(0.2f, AssignCommand(oIP, PlaySound(sYawn, TRUE)));		
			FadeToBlack(oPC, FADE_SPEED_SLOW, 7.0f);
			DelayCommand(6.0f, AssignCommand(oPC, PlaySound(sWake, TRUE)));
			SetPlotFlag(oIP, FALSE);		
			DestroyObject(oIP, 6.2f);
			
			object oWTrig = GetNearestObjectByTag("rest_warm", oPC);
			object oWPers = GetFirstInPersistentObject(oWTrig);

			while (GetIsObjectValid(oWPers))
			{
				if (oWPers == oPC) SetLocalInt(oPC, "warm", TRUE);
				oWPers = GetNextInPersistentObject(oWTrig);
			}
		}
	}
	
	if (GetLocalInt(oPC, "warm") && nRestEvent == REST_EVENTTYPE_REST_FINISHED)
	{
		DelayCommand(1.0f, ApplyEffectToParty(oPC, TRUE));
		DelayCommand(2.0f, FloatingTextStringOnCreature("<color=lime>You are well-rested! (Fortitude Bonus)", oPC, FALSE));
		DelayCommand(2.0f, DeleteLocalInt(oPC, "warm"));
	}
	
	else if (nRestEvent == REST_EVENTTYPE_REST_FINISHED)
	{
		DelayCommand(1.0f, ApplyEffectToParty(oPC));
		DelayCommand(2.0f, FloatingTextStringOnCreature("<color=aqua>The frigid cold saps your soul!", oPC, FALSE));
	}
}
2 Likes

A few tweaks and adjustments using your solution and…bingo :slight_smile:

I’ve played around with this in-game, tried to break it, with no success. Thanks for putting this together, it works exactly how I hoped :slight_smile: A spot of DIY to do, then I’ll sit down and put together the short scene where Faenwen guides you through the rest system changes :slight_smile:


After resting in a cold area


After resting in a warm area

EDIT: Other modules I have played have handled cold differently. A common way has been to deal cold damage per 6 seconds which can be irritating. Healing up via rest and then slapping down HP by 25% seems better to me. The character above is saved from UA and has skipped the item strip at the start of this campaign, so don’t expect characters to be blocking the cold damage or regenerating at the rate he is from this early stage.

5 Likes

kevL is the mad genius behind the functionality of it. I can’t take much credit for it beyond the graphics.

Here is the most stripped down version of it:
http://www.dethguild.com/wp-content/uploads/files/nwn/modules/ToH_thirst_system_by_kevL.zip

3 Likes

Resting intro done. Now on with the story! A few encounters to place in the area. Maybe a few hidden goodies to distract :slight_smile:


Well-rested, it’s time to set off!

2 Likes

I’ve had this issue before (see pic - lootbags are not selectable, only sparkle vfx shows)

Something in the placeables 2da needs fixing but I can’t recall what im looking for. Checked the entries for “lootbag” but can’t spot anything wrong. Suggestions?

1 Like

(sry) cant remember if this works but found it buried on my hardrive

void ClearBagSparkles()
{
	object o = GetFirstObjectInArea();
	while (GetIsObjectValid(o))
	{
		if (GetTag(o) == "BodyBag")
			RemoveSEFFromObject(o, "fx_lootbag"); // <---

		o = GetNextObjectInArea();
	}
}

 
or do you mean there should be a lootbag but there isn’t?

1 Like

@MERP_UK Are you using the placeable.2da from the UTTRules_v6.hak?

@travus, I am currently using the placeables 2da from the placeables.hak. I discovered I had multiple 2das when I noticed a load of the placeables in the cornucopia pack were not working.

@kevL_s, yes, there should be a lootbag there. I noticed the name “bodybag” in your script…I didnt search for that in the 2da so maybe thats the answer.

Here’s a cleaned-up version of that 2da - should fix the lootbag problem (i hope).

1 Like

Thanks, I’ll take a look over it tomorrow. I had this issue in the early days of UA and I solved it but can’t remember what I did with the 2da. Was it an error with the bodybag entry by any chance? Since @kevL_s mentioned it I felt like that was the entry I needed.

This cleaned-up version has lines 13-18 added to it for LootBag1-6. The previous 2da didn’t have that data.

2 Likes