starlit  Check-in [e829ca194a]

Overview
Comment:plant growth, edibles, fixes
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: e829ca194a0a1cb867d8e29e733a69d13ce75e2697dc907bb03e0ea83c1ab2b0
User & Date: lexi on 2024-05-02 00:22:47
Other Links: manifest | tags
Context
2024-05-02
20:27
check in missing mod, add forest biome, racial powers, overlays (untested) check-in: 6deb9bedbc user: lexi tags: trunk
00:22
plant growth, edibles, fixes check-in: e829ca194a user: lexi tags: trunk
2024-05-01
16:25
fixes, sounds; add license info check-in: 0e67c606c9 user: lexi tags: trunk
Changes

Modified mods/starlit-electronics/sw.lua from [e776ef774d] to [eb892cff12].

129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
	kind = 'suitPower', powerKind = 'active';
	desc = 'An open-source program used in its various forks and iterations all across human-inhabited space and beyond. Rumored to contain fragments of code stolen from the nanoware of the Greater Races by an elusive infoterrorist.';
	size = 500e3;
	cost = {
		cycles = 100e6;
		ram = 500e6;
	};
	run = shredder{range=2, powerDraw=200};
})

starlit.item.sw.link('starlit_electronics:compile_commune', {
	name = 'Compile Matter';
	kind = 'suitPower', powerKind = 'direct';
	desc = "A basic suit matter compiler program, rather slow but ruthlessly optimized for power- and memory-efficiency by some of the Commune's most fanatic coders.";
	size = 700e3;







|







129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
	kind = 'suitPower', powerKind = 'active';
	desc = 'An open-source program used in its various forks and iterations all across human-inhabited space and beyond. Rumored to contain fragments of code stolen from the nanoware of the Greater Races by an elusive infoterrorist.';
	size = 500e3;
	cost = {
		cycles = 100e6;
		ram = 500e6;
	};
	run = shredder{range=3, powerDraw=200};
})

starlit.item.sw.link('starlit_electronics:compile_commune', {
	name = 'Compile Matter';
	kind = 'suitPower', powerKind = 'direct';
	desc = "A basic suit matter compiler program, rather slow but ruthlessly optimized for power- and memory-efficiency by some of the Commune's most fanatic coders.";
	size = 700e3;

Modified mods/starlit/init.lua from [c40c4aaae1] to [e52f2bba90].

46
47
48
49
50
51
52

53
54
55
56
57
58
59
60
61
62
63
64
65
...
386
387
388
389
390
391
392
393
394


395
396
397
398
399
400
401
...
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433




434
435
436
437
438
439
	liveUI = {
		-- cached subset of activeUI containing those UIs needing live updates
	};

	interface = lib.registry.mk 'starlit:interface';
	item = {
		food = lib.registry.mk 'starlit:food';

	};

	region = {
		radiator = {
			store = AreaStore();
			emitters = {}
		};
	};

	-- standardized effects
	fx = {};

	type = {};
................................................................................
})
minetest.register_item("starlit:_hand_dig", {
	type = "none",
	wield_image = "wieldhand.png",
	wield_scale = {x=1,y=1,z=2.5},
	tool_capabilities = {
		groupcaps = {
			plant = {maxlevel=1, times = {.50,.5,.5}};
			dirt = {maxlevel=1, times = {2.5,1,1}};


		};
	}
})

minetest.register_on_player_inventory_action(function(luser, act, inv, p)
	local name = luser:get_player_name()
	local user = starlit.activeUsers[name]
................................................................................
		-- cranked by similarly
	end
	return delta
end, true)

function minetest.handle_node_drops(pos, drops, digger)
	local function jitter(pos)
		local function r(x) return x+math.random(-0.2, 0.2) end
		return vector.new(
			r(pos.x),
			r(pos.y),
			r(pos.z)
		)
	end
	for i, it in ipairs(drops) do
		minetest.add_item(jitter(pos), it)




	end
end


-- TODO timer iterates live UI








>





|







 







|
|
>
>







 







|







|
>
>
>
>






46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
...
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
...
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
	liveUI = {
		-- cached subset of activeUI containing those UIs needing live updates
	};

	interface = lib.registry.mk 'starlit:interface';
	item = {
		food = lib.registry.mk 'starlit:food';
		seed = lib.registry.mk 'starlit:seed';
	};

	region = {
		radiator = {
			store = AreaStore();
			emitters = {};
		};
	};

	-- standardized effects
	fx = {};

	type = {};
................................................................................
})
minetest.register_item("starlit:_hand_dig", {
	type = "none",
	wield_image = "wieldhand.png",
	wield_scale = {x=1,y=1,z=2.5},
	tool_capabilities = {
		groupcaps = {
			plant = {maxlevel=1, times = {.50}};
			dirt = {maxlevel=1, times = {2.5}};

			log = {maxlevel=1, times = {1}};
		};
	}
})

minetest.register_on_player_inventory_action(function(luser, act, inv, p)
	local name = luser:get_player_name()
	local user = starlit.activeUsers[name]
................................................................................
		-- cranked by similarly
	end
	return delta
end, true)

function minetest.handle_node_drops(pos, drops, digger)
	local function jitter(pos)
		local function r(x) return x+math.random(-0.01, 0.01) end
		return vector.new(
			r(pos.x),
			r(pos.y),
			r(pos.z)
		)
	end
	for i, it in ipairs(drops) do
		local it = minetest.add_item(jitter(pos), it)
		local dp = vector.new(0,0,0)
		if digger then dp = digger:get_pos() end
		local delta = dp - it:get_pos()
		it:add_velocity(vector.new(delta.x,0,delta.z));
	end
end


-- TODO timer iterates live UI

Modified mods/starlit/interfaces.lua from [5877ccf3fb] to [497adf50ee].

345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
				local tb = {
					kind = 'vert', mode = 'sw';
					padding = 0.5, 
					{kind = 'hztl', padding = 0.25;
						{kind = 'label', text = 'Name', w = 2, h = barh};
						{kind = 'label', text = user.persona.name, w = 4, h = barh}};
				}
				local statBars = {'hunger', 'thirst', 'fatigue', 'morale', 'irradiation', 'illness'}
				for idx, id in ipairs(statBars) do
					local s = starlit.world.stats[id]
					local amt, sv = user:effectiveStat(id)
					local min, max = starlit.world.species.statRange(user.persona.species, user.persona.speciesVariant, id)
					local st = string.format('%s / %s', s.desc(amt, true), s.desc(max))
					table.insert(tb, {kind = 'hztl', padding = 0.25;
						{kind = 'label', w=2, h=barh, text = s.name};







|







345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
				local tb = {
					kind = 'vert', mode = 'sw';
					padding = 0.5, 
					{kind = 'hztl', padding = 0.25;
						{kind = 'label', text = 'Name', w = 2, h = barh};
						{kind = 'label', text = user.persona.name, w = 4, h = barh}};
				}
				local statBars = {'nutrition', 'hydration', 'fatigue', 'morale', 'irradiation', 'illness'}
				for idx, id in ipairs(statBars) do
					local s = starlit.world.stats[id]
					local amt, sv = user:effectiveStat(id)
					local min, max = starlit.world.species.statRange(user.persona.species, user.persona.speciesVariant, id)
					local st = string.format('%s / %s', s.desc(amt, true), s.desc(max))
					table.insert(tb, {kind = 'hztl', padding = 0.25;
						{kind = 'label', w=2, h=barh, text = s.name};

Modified mods/starlit/species.lua from [642ae8f101] to [b30e9eb59a].

45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
...
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
...
184
185
186
187
188
189
190


191
192
193
194
195
196
197

					return {lining, plate, skin, skin, eye, hair}
				end;
				stats = {
					psiRegen = 1.3;
					psiPower = 1.2;
					psi = 1.2;
					hunger = .8; -- women have smaller stomachs
					thirst = .8;
					staminaRegen = 1.0;
					morale = 0.8; -- you are not She-Bear Grylls
				};
				traits = {
					health = 400;
					lungCapacity = .6;
					irradiation = 0.8; -- you are smaller, so it takes less rads to kill ya
					sturdiness = 0; -- women are more fragile and thus susceptible to blunt force trauma
					metabolism = 1800e3 / 24 / 60 / 60; --kCal/s
					painTolerance = 0.4;
					dehydration = 3; -- mL/s
				};
			};
			male = {
				name = 'Human Male';
				eyeHeight = 1.6;
				stats = {
					psiRegen = 1.0;
					psiPower = 1.0;
					psi = 1.0;
					hunger = 1.0;
					thirst = 1.0;
					staminaRegen = .7; -- men are strong but have inferior endurance
				};
				traits = {
					health = 500;
					painTolerance = 1.0;
					lungCapacity = 1.0;
					sturdiness = 0.3;
					metabolism = 2200e3 / 24 / 60 / 60; --Cal/s
					dehydration = 5; -- mL/s
				};
			};
		};
		traits = {};
	};
}

................................................................................
		if base == true then
			base = max
		elseif base == false then
			base = min
		end

	end
	return min, max, base
end

-- set the necessary properties and create a persona for a newspawned entity
function starlit.world.species.birth(pSpecies, pVariant, entity, circumstances)
	circumstances = circumstances or {}
	local sp,var = spLookup(pSpecies, pVariant)

................................................................................
	end
	local ps = starlit.world.species.mkPersonaFor(pSpecies,pVariant)
	local startingHP = pct('health', 1.0)
	if circumstances.injured    then startingHP = pct('health', circumstances.injured) end
	if circumstances.psiCharged then ps.statDeltas.psi = pct('psi', circumstances.psiCharged) end
	for k,v in pairs(starlit.world.stats) do ps.statDeltas[k] = 0 end
	ps.statDeltas.warmth = 20 -- don't instantly start dying of frostbite



	entity:set_properties{hp_max = var.traits.health or sp.traits.health}
	entity:set_hp(startingHP, 'initial hp')
	return ps
end

function starlit.world.species.paramsFromTable(pSpecies, tbl)







|
|








|

|









|
|







|
|







 







|







 







>
>







45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
...
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
...
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199

					return {lining, plate, skin, skin, eye, hair}
				end;
				stats = {
					psiRegen = 1.3;
					psiPower = 1.2;
					psi = 1.2;
					nutrition = .8; -- women have smaller stomachs
					hydration = .8;
					staminaRegen = 1.0;
					morale = 0.8; -- you are not She-Bear Grylls
				};
				traits = {
					health = 400;
					lungCapacity = .6;
					irradiation = 0.8; -- you are smaller, so it takes less rads to kill ya
					sturdiness = 0; -- women are more fragile and thus susceptible to blunt force trauma
					metabolism = .150; -- kCal/s
					painTolerance = 0.4;
					dehydration = 10e-4; -- L/s
				};
			};
			male = {
				name = 'Human Male';
				eyeHeight = 1.6;
				stats = {
					psiRegen = 1.0;
					psiPower = 1.0;
					psi = 1.0;
					nutrition = 1.0;
					hydration = 1.0;
					staminaRegen = .7; -- men are strong but have inferior endurance
				};
				traits = {
					health = 500;
					painTolerance = 1.0;
					lungCapacity = 1.0;
					sturdiness = 0.3;
					metabolism = .150; -- kCal/s
					dehydration = 15e-4; -- L/s
				};
			};
		};
		traits = {};
	};
}

................................................................................
		if base == true then
			base = max
		elseif base == false then
			base = min
		end

	end
	return min, max, base or 0
end

-- set the necessary properties and create a persona for a newspawned entity
function starlit.world.species.birth(pSpecies, pVariant, entity, circumstances)
	circumstances = circumstances or {}
	local sp,var = spLookup(pSpecies, pVariant)

................................................................................
	end
	local ps = starlit.world.species.mkPersonaFor(pSpecies,pVariant)
	local startingHP = pct('health', 1.0)
	if circumstances.injured    then startingHP = pct('health', circumstances.injured) end
	if circumstances.psiCharged then ps.statDeltas.psi = pct('psi', circumstances.psiCharged) end
	for k,v in pairs(starlit.world.stats) do ps.statDeltas[k] = 0 end
	ps.statDeltas.warmth = 20 -- don't instantly start dying of frostbite
	ps.statDeltas.nutrition = 2000 -- shoulda packed more MRE :c
	ps.statDeltas.hydration = 3 -- stay hydrated uwu

	entity:set_properties{hp_max = var.traits.health or sp.traits.health}
	entity:set_hp(startingHP, 'initial hp')
	return ps
end

function starlit.world.species.paramsFromTable(pSpecies, tbl)

Modified mods/starlit/stats.lua from [523263fc9a] to [c485cf1b8a].

1

2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
..
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
local lib = starlit.mod.lib


local function U(unit, prec, fixed)
	local trunc = 2
	if fixed then
		return function(amt, excludeUnit)
			local ta = lib.math.trim(amt/prec, trunc)
			if excludeUnit then return tostring(ta) end
			return string.format("%s %s", ta, unit)
		end
	else
		return function(amt, excludeUnit)
			local ta = lib.math.trim(amt/prec, trunc)
			if excludeUnit then return tostring(ta) end
			return lib.math.si(unit, amt/prec, nil, nil, trunc)
		end
................................................................................
local function C(h, s, l)
	return lib.color {hue = h, sat = s or 1, lum = l or .7}
end
starlit.world.stats = {
	psi        = {min = 0, max = 500, base = 0, desc = U('ψ', 10), color = C(320), name = 'Numina'};
	-- numina is measured in daψ
	warmth     = {min = -1000, max = 1000, base = 0, desc = U('°C', 10, true), color = C(5), name = 'Warmth'};
	-- warmth in measured in °C×10
	fatigue    = {min = 0, max = 76 * 60, base = 0, desc = U('hr', 60, true), color = C(288,.3,.5), name = 'Fatigue'};
	-- fatigue is measured in minutes one needs to sleep to cure it
	stamina    = {min = 0, max = 20 * 100, base = true, desc = U('m', 100), color = C(88), name = 'Stamina'};
	-- stamina is measured in how many 10th-nodes (== cm) one can sprint
	hunger     = {min = 0, max = 2000e3, base = 0, desc = U('kCal', 1000, true), color = C(43,.5,.4), name = 'Hunger'};
	-- hunger is measured in calories one must consume to cure it. at a 2kCal deficit, you start dying
	thirst     = {min = 0, max = 4e3, base = 0, desc = U('L', 1e3), color = C(217, .25,.4), name = 'Thirst'};
	-- thirst is measured in mL of H²O required to cure it
	morale     = {min = 0, max = 24 * 60 * 10, base = true, desc = U('hr', 60, true), color = C(0,0,.8), name = 'Morale'};
	-- morale is measured in minutes. e.g. at base rate morale degrades by
	-- 60 points every hour. morale can last up to 10 days
	irradiation = {min = 0, max = 20000, base = 0, desc = U('Gy', 1000), color = C(141,1,.5), name = 'Irradiation'};
	-- irrad is measured is milligreys
	-- 1Gy counters natural healing
	-- ~3Gy counters basic nanomedicine
	-- 5Gy causes death within two weeks without nanomedicine
	-- radiation speeds up psi regen
	-- morale drain doubles with each 2Gy
	illness    = {min = 0, max = 1000, base = 0, desc = U('%', 10, true), color = C(71,.4,.25), name = 'Illness'};
	-- as illness increases, maximum stamina and health gain a corresponding limit
	-- illness is increased by certain conditions, and decreases on its own as your
	-- body heals when those conditions wear off. some drugs can lower accumulated illness
	-- but illness-causing conditions require specific cures
	-- illness also causes thirst and fatigue to increase proportionately
}

>







|







 







|




|
|
|
|



|













1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
..
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
local lib = starlit.mod.lib
local T,G = lib.marshal.t, lib.marshal.g

local function U(unit, prec, fixed)
	local trunc = 2
	if fixed then
		return function(amt, excludeUnit)
			local ta = lib.math.trim(amt/prec, trunc)
			if excludeUnit then return tostring(ta) end
			return string.format("%s%s", ta, unit)
		end
	else
		return function(amt, excludeUnit)
			local ta = lib.math.trim(amt/prec, trunc)
			if excludeUnit then return tostring(ta) end
			return lib.math.si(unit, amt/prec, nil, nil, trunc)
		end
................................................................................
local function C(h, s, l)
	return lib.color {hue = h, sat = s or 1, lum = l or .7}
end
starlit.world.stats = {
	psi        = {min = 0, max = 500, base = 0, desc = U('ψ', 10), color = C(320), name = 'Numina'};
	-- numina is measured in daψ
	warmth     = {min = -1000, max = 1000, base = 0, desc = U('°C', 10, true), color = C(5), name = 'Warmth'};
	-- warmth in measured in d°C
	fatigue    = {min = 0, max = 76 * 60, base = 0, desc = U('hr', 60, true), color = C(288,.3,.5), name = 'Fatigue'};
	-- fatigue is measured in minutes one needs to sleep to cure it
	stamina    = {min = 0, max = 20 * 100, base = true, desc = U('m', 100), color = C(88), name = 'Stamina'};
	-- stamina is measured in how many 10th-nodes (== cm) one can sprint
	nutrition  = {min = 0, max = 8000, base = 0, desc = U('kCal', 1, true), color = C(43,.5,.4), name = 'Nutrition', srzType = T.decimal};
	-- hunger is measured in kcalories one must consume to cure it. at 0, you start dying
	hydration  = {min = 0, max = 4, base = 0, desc = U('L', 1), color = C(217, .25,.4), name = 'Hydration', srzType = T.decimal};
	-- thirst is measured in L of H²O required to cure it
	morale     = {min = 0, max = 24 * 60 * 10, base = true, desc = U('hr', 60, true), color = C(0,0,.8), name = 'Morale'};
	-- morale is measured in minutes. e.g. at base rate morale degrades by
	-- 60 points every hour. morale can last up to 10 days
	irradiation = {min = 0, max = 10, base = 0, desc = U('Gy', 1), color = C(141,1,.5), name = 'Irradiation', srzType = T.decimal};
	-- irrad is measured is milligreys
	-- 1Gy counters natural healing
	-- ~3Gy counters basic nanomedicine
	-- 5Gy causes death within two weeks without nanomedicine
	-- radiation speeds up psi regen
	-- morale drain doubles with each 2Gy
	illness    = {min = 0, max = 1000, base = 0, desc = U('%', 10, true), color = C(71,.4,.25), name = 'Illness'};
	-- as illness increases, maximum stamina and health gain a corresponding limit
	-- illness is increased by certain conditions, and decreases on its own as your
	-- body heals when those conditions wear off. some drugs can lower accumulated illness
	-- but illness-causing conditions require specific cures
	-- illness also causes thirst and fatigue to increase proportionately
}

Modified mods/starlit/terrain.lua from [43cb3c61b6] to [033036f747].

4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
..
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
starlit.terrain = {}
local soilSounds = {
	footstep = 'default-dirt-footstep';
	dig = 'default-dig-crumbly';
	dug = 'default-dug-node';
}
local sandSounds = {
	footstep = 'default-sand-footstep';
	dig = 'default-dig-crumbly';
	dug = 'default-dug-node';
}
local grassSounds = {
	footstep = 'default-grass-footstep';
	dig = 'default-dig-crumbly';
	dug = 'default-dug-node';
................................................................................
minetest.register_node('starlit:soil', {
	description = T 'Soil';
	tiles = {'default_dirt.png'};
	groups = {dirt = 1};
	drop = '';
	sounds = soilSounds;
	_starlit = {
		onDestroy = function() end;
		kind = 'block';
		elements = {};
	};
})


minetest.register_node('starlit:sand', {







|







 







<







4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
..
21
22
23
24
25
26
27

28
29
30
31
32
33
34
starlit.terrain = {}
local soilSounds = {
	footstep = 'default-dirt-footstep';
	dig = 'default-dig-crumbly';
	dug = 'default-dug-node';
}
local sandSounds = {
	footstep = {name='default-sand-footstep',gain=0.1};
	dig = 'default-dig-crumbly';
	dug = 'default-dug-node';
}
local grassSounds = {
	footstep = 'default-grass-footstep';
	dig = 'default-dig-crumbly';
	dug = 'default-dug-node';
................................................................................
minetest.register_node('starlit:soil', {
	description = T 'Soil';
	tiles = {'default_dirt.png'};
	groups = {dirt = 1};
	drop = '';
	sounds = soilSounds;
	_starlit = {

		kind = 'block';
		elements = {};
	};
})


minetest.register_node('starlit:sand', {

Modified mods/starlit/user.lua from [a0e5424f99] to [fe75c1df99].

72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95



96
97


98
99
100
101
102
103
104
...
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483

484
485
486
487
488
489
490
491
...
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
...
840
841
842
843
844
845
846
847
848














849
850
851
852
853
854
855
		pushPersona = function(self)
			local s = userStore(self.entity)
			s.write('persona', self.persona)
		end;
		uiColor = function(self) return lib.color {hue=238,sat=.5,lum=.5} end;
		statDelta = function(self, stat, d, cause, abs)
			local dt = self.persona.statDeltas
			local base
			if abs then
				local min, max
				min, max, base = self:statRange(stat)
				if     d == true  then d = max
				elseif d == false then d = min end
			end
			if stat == 'health' then
				self.entity:set_hp(abs and d or (self.entity:get_hp() + d), cause)
			elseif stat == 'breath' then
				self.entity:set_breath(abs and d or (self.entity:get_breath() + d))
			else
				if abs then
					dt[stat] = d - base
				else
					dt[stat] = dt[stat] + d
				end



				self:pushPersona()
			end


			self:updateHUD()
			-- TODO trigger relevant animations?
		end;
		lookupSpecies = function(self)
			return starlit.world.species.lookup(self.persona.species, self.persona.speciesVariant)
		end;
		phenoTrait = function(self, trait, dflt)
................................................................................

			giveGifts('main', gifts.carry)

			self:reconfigureSuit()

			-- i feel like there has to be a better way
			local cx = math.random(-500,500)
			local startPoint
			repeat local temp = -100
				local cz = math.random(-500,500)
				local cy = minetest.get_spawn_level(cx, cz)
				if cy then
					startPoint = vector.new(cx,cy,cz)
					temp = starlit.world.climate.eval(startPoint,.5,.5).surfaceTemp
				end

				if cx > 10000 then break end -- avoid infiniloop in pathological conditions
			until temp > -2
			self.entity:set_pos(startPoint)
			meta:set_string('starlit_spawn', startPoint:to_string())
		end;
		onDie = function(self, reason)
			local inv = self.entity:get_inventory()
			local where = self.entity:get_pos()
................................................................................
						minetest.item_drop(o, self.entity, where)
					end
				end
				inv:set_list(lst, {})
			end
			dropInv 'main'
			dropInv 'starlit_suit'
			self:statDelta('psi',     0, 'death', true)
			self:statDelta('hunger',  0, 'death', true)
			self:statDelta('thirst',  0, 'death', true)
			self:statDelta('fatigue', 0, 'death', true)
			self:statDelta('stamina', 0, 'death', true)
			self:updateSuit()
		end;
		onRespawn = function(self)
			local meta = self.entity:get_meta()
			self.entity:set_pos(vector.from_string(meta:get_string'starlit_spawn'))
			self:updateSuit()
			return true
................................................................................
		local bmr = p:trait 'metabolism' * biointerval
		-- TODO apply modifiers

		local dehydration = p:trait 'dehydration' * biointerval
		-- you dehydrate faster in higher temp
		dehydration = dehydration * math.max(1, starlit.world.climate.temp(u.entity:get_pos()) / 10)

		u:statDelta('hunger', bmr)
		u:statDelta('thirst', dehydration)














	end
end)

local cbit = {
	up   = 0x001;
	down = 0x002;
	left = 0x004;







|

<
<













>
>
>


>
>







 







|







>
|







 







|
|
|
|
|







 







|
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>







72
73
74
75
76
77
78
79
80


81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
...
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
...
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
...
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
		pushPersona = function(self)
			local s = userStore(self.entity)
			s.write('persona', self.persona)
		end;
		uiColor = function(self) return lib.color {hue=238,sat=.5,lum=.5} end;
		statDelta = function(self, stat, d, cause, abs)
			local dt = self.persona.statDeltas
			local min, max, base = self:statRange(stat)
			if abs then


				if     d == true  then d = max
				elseif d == false then d = min end
			end
			if stat == 'health' then
				self.entity:set_hp(abs and d or (self.entity:get_hp() + d), cause)
			elseif stat == 'breath' then
				self.entity:set_breath(abs and d or (self.entity:get_breath() + d))
			else
				if abs then
					dt[stat] = d - base
				else
					dt[stat] = dt[stat] + d
				end

				if     dt[stat]+base > max then dt[stat] = max-base
				elseif dt[stat]+base < min then dt[stat] = min-base end
				self:pushPersona()
			end


			self:updateHUD()
			-- TODO trigger relevant animations?
		end;
		lookupSpecies = function(self)
			return starlit.world.species.lookup(self.persona.species, self.persona.speciesVariant)
		end;
		phenoTrait = function(self, trait, dflt)
................................................................................

			giveGifts('main', gifts.carry)

			self:reconfigureSuit()

			-- i feel like there has to be a better way
			local cx = math.random(-500,500)
			local iter, startPoint = 1
			repeat local temp = -100
				local cz = math.random(-500,500)
				local cy = minetest.get_spawn_level(cx, cz)
				if cy then
					startPoint = vector.new(cx,cy,cz)
					temp = starlit.world.climate.eval(startPoint,.5,.5).surfaceTemp
				end
				iter = iter + 1
				if iter > 100 then break end -- avoid infiniloop in pathological conditions
			until temp > -2
			self.entity:set_pos(startPoint)
			meta:set_string('starlit_spawn', startPoint:to_string())
		end;
		onDie = function(self, reason)
			local inv = self.entity:get_inventory()
			local where = self.entity:get_pos()
................................................................................
						minetest.item_drop(o, self.entity, where)
					end
				end
				inv:set_list(lst, {})
			end
			dropInv 'main'
			dropInv 'starlit_suit'
			self:statDelta('psi',          0, 'death', true)
			self:statDelta('nutrition', 1500, 'death', true)
			self:statDelta('hydration',    2, 'death', true)
			self:statDelta('fatigue',      0, 'death', true)
			self:statDelta('stamina',      0, 'death', true)
			self:updateSuit()
		end;
		onRespawn = function(self)
			local meta = self.entity:get_meta()
			self.entity:set_pos(vector.from_string(meta:get_string'starlit_spawn'))
			self:updateSuit()
			return true
................................................................................
		local bmr = p:trait 'metabolism' * biointerval
		-- TODO apply modifiers

		local dehydration = p:trait 'dehydration' * biointerval
		-- you dehydrate faster in higher temp
		dehydration = dehydration * math.max(1, starlit.world.climate.temp(u.entity:get_pos()) / 10)

		u:statDelta('nutrition', -bmr)
		u:statDelta('hydration', -dehydration)

		if u:effectiveStat 'nutrition' == 0 then
			-- starvation
		end

		if u:effectiveStat 'hydration' == 0 then
			-- dying of thirst
		end

		local rads = u:effectiveStat 'irradiation'
		if rads > 0 then
			u:statDelta('irradiation', -0.0001 * biointerval)
		end

	end
end)

local cbit = {
	up   = 0x001;
	down = 0x002;
	left = 0x004;

Modified mods/starlit/world.lua from [c6867ae3a2] to [4823845880].

137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152

153
154
155
156
157
158
159
160
161
162
163
164
165
...
231
232
233
234
235
236
237
























			base.node_dig_prediction = stageID(st.swap)
			function base.after_dig_node(pos, node, digger)
				node.name = stageID(st.swap)
				minetest.swap_node(pos, node)
				return true
			end
		end
		if st.biolum then
			base.light_source = math.floor(st.biolum * (n/stageCt))
		end
		return base
	end
	for i, v in ipairs(b.stages) do
		local n = regStage(i, v)
		b.stageNodes[i] = n
		minetest.register_node(stageID(i), n)

	end
	b.fullyGrown = stageID(stageCt)

	local dec = {
		deco_type = 'simple';
		decoration = b.fullyGrown;
		height = 1;
		param2 = b.meshOpt or 0;
	}
	for k,v in pairs(b.decoration) do dec[k] = v end
	b.decoration = minetest.register_decoration(dec)
end)

................................................................................
			end
			-- for every degree of difference you suffer 2 points of damage/s
			local dmg = math.ceil(dv * 2)
			user:statDelta('health', -dmg)
		end
	end
end)































|
<
<




<

>





|







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
137
138
139
140
141
142
143
144


145
146
147
148

149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
...
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
			base.node_dig_prediction = stageID(st.swap)
			function base.after_dig_node(pos, node, digger)
				node.name = stageID(st.swap)
				minetest.swap_node(pos, node)
				return true
			end
		end
		if st.biolum then base.light_source = st.biolum; end


		return base
	end
	for i, v in ipairs(b.stages) do
		local n = regStage(i, v)

		minetest.register_node(stageID(i), n)
		b.stageNodes[i] = stageID(i)
	end
	b.fullyGrown = stageID(stageCt)

	local dec = {
		deco_type = 'simple';
		decoration = b.stageNodes;
		height = 1;
		param2 = b.meshOpt or 0;
	}
	for k,v in pairs(b.decoration) do dec[k] = v end
	b.decoration = minetest.register_decoration(dec)
end)

................................................................................
			end
			-- for every degree of difference you suffer 2 points of damage/s
			local dmg = math.ceil(dv * 2)
			user:statDelta('health', -dmg)
		end
	end
end)


world.ecology.trees.foreach('starlit:tree-gen', {}, function(id, t)
	local dec = {
		deco_type = 'lsystem';
		treedef = t.def;
	}
	for k,v in pairs(t.decorate) do dec[k]=v end
	minetest.register_decoration(dec)
end)

minetest.register_abm {
	label = "plant growth";
	nodenames = {'group:plant_grow'};
	chance = 15;
	interval = 20;
	catch_up = true;
	action = function(pos, node)
		local def = minetest.registered_nodes[node.name]._starlit.plant
		local plant = starlit.world.ecology.plants.db[def.id]
		local nextStage = plant.stageNodes[def.stage + 1]
		minetest.swap_node(pos, {name=nextStage})
	end;
}

Modified mods/vtlib/marshal.lua from [500f446f0a] to [2822b4a0ba].

134
135
136
137
138
139
140
141
142
143
144
145



146

147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
...
198
199
200
201
202
203
204

205
206
207
208
209
210
211
-- generic type constructors --
-------------------------------

function G.int(bits,signed)
	local bytes = math.ceil(bits / 8)
	local max = 2 ^ bits
	local spoint = math.floor(max/2)
	return {
		sz = bytes;
		name = string.format("%sint<%s>",
			signed and 's' or 'u', bits
		);



		enc = function(obj)

			obj = obj or 0
			local val = math.abs(obj)
			local str = ''
			if signed then
				local max = math.floor(max / 2)
				if (obj > max) or (obj < (0-(max+1))) then
					return m.err.domain end
				if obj < 0 then val = val + spoint end
				-- e.g. for 8bit: 0x80 == -1; 0xFF = -128
			else
				if val > max then return m.err.domain end
			end
			for i=1,bytes do
				local n = math.fmod(val, 0x100)
				str = str .. string.char(n)
				val = math.floor(val / 0x100)
			end
			return str
................................................................................
		def = ...
	end
	name = 'struct' .. (name and ':' .. name or '');
	report('defining struct name=%q fields=%s', name, dump(def))
	return {
		name = name;
		enc = function(obj)

			local enc = m.streamEncoder()
			local n = 0
			for k,ty in pairs(def) do n=n+1
				if obj[k] == nil then error('missing key '..dump(k)..' for type '..ty.name) end
				local encoded = ty.enc(obj[k])
				enc.push(T.u8.enc(#k), size.enc(#encoded), k, encoded)
			end







<
<
|


>
>
>

>






|



|







 







>







134
135
136
137
138
139
140


141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
...
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
-- generic type constructors --
-------------------------------

function G.int(bits,signed)
	local bytes = math.ceil(bits / 8)
	local max = 2 ^ bits
	local spoint = math.floor(max/2)


	local name = string.format("%sint<%s>",
			signed and 's' or 'u', bits
		);
	return {
		name = name;
		sz = bytes;
		enc = function(obj)
			report('encoding %s value=%s', name, dump(obj))
			obj = obj or 0
			local val = math.abs(obj)
			local str = ''
			if signed then
				local max = math.floor(max / 2)
				if (obj > max) or (obj < (0-(max+1))) then
					return error('domain error') end
				if obj < 0 then val = val + spoint end
				-- e.g. for 8bit: 0x80 == -1; 0xFF = -128
			else
				if val > max then error('domain error') end
			end
			for i=1,bytes do
				local n = math.fmod(val, 0x100)
				str = str .. string.char(n)
				val = math.floor(val / 0x100)
			end
			return str
................................................................................
		def = ...
	end
	name = 'struct' .. (name and ':' .. name or '');
	report('defining struct name=%q fields=%s', name, dump(def))
	return {
		name = name;
		enc = function(obj)
		report('encoding struct name=%q vals=%s', name, dump(obj))
			local enc = m.streamEncoder()
			local n = 0
			for k,ty in pairs(def) do n=n+1
				if obj[k] == nil then error('missing key '..dump(k)..' for type '..ty.name) end
				local encoded = ty.enc(obj[k])
				enc.push(T.u8.enc(#k), size.enc(#encoded), k, encoded)
			end

Modified mods/vtlib/ui.lua from [121fdb8a0d] to [765cced2b5].

42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
	};

	tooltipper = function(dui)
		-- takes a configuration table mapping affinities to colors.
		-- 'neutral' is the only required affinity
		return function(a)
			local color = a.color and a.color:readable(0.65, 1.0)
			if color == nil then color = l.color(136,158,177) end
			local str = a.title
			if a.desc then
				str = str .. '\n' .. color:fmt(minetest.wrap_text(a.desc,60))
			end
			if a.props then
				-- str = str .. '\n'
				for _,prop in pairs(a.props) do







|







42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
	};

	tooltipper = function(dui)
		-- takes a configuration table mapping affinities to colors.
		-- 'neutral' is the only required affinity
		return function(a)
			local color = a.color and a.color:readable(0.65, 1.0)
			if color == nil then color = l.color(.5,.5,.5) end
			local str = a.title
			if a.desc then
				str = str .. '\n' .. color:fmt(minetest.wrap_text(a.desc,60))
			end
			if a.props then
				-- str = str .. '\n'
				for _,prop in pairs(a.props) do