Page 1 of 1

Making Splinter clolonies more alive

Posted: Wed Aug 06, 2025 3:30 pm
by TSNH
Hello to everyone on this forum,

When playing I always found those human and teros splinter colonies too easy to capture and generally not much different from just native races.

So I've made a mod that makes them behave like regular empires, except:
  • They can't colonize new planets
  • They don't build new improvements on their planet
  • They have simplified diplomacy as they used to
  • Their fleets are not aggressive towards pirates
Which means they now can:
  • Research (although slowly)
  • build ships (and defend themselves in early game)
  • build outposts
In Lua state\Setup\setup_star_specials.lua

Make a new type of economy for splinter empires by adding a new field
Remove the highly limiting monster economy

Code: Select all

  blank.monster_economy=true
Add a new one (without any restrictions yet)

Code: Select all

  blank.spl_economy=true  
which means:

Change:

Code: Select all

local function new_minor_empire(species,planet)

  local count=0

  for i,empire in pairs | all_empires

    if empire.minor_faction==species
      count++
    end

  end

   local blank = blank_empire( 
    format("%s_minor_%d",species,count+1),  -- this should be replaced by setup_splinter_leader()
    --format('Independent (%s)',capitalize | species),
    species,'cyan')

  blank.monster_economy=true     
  blank.minor_faction=species


  all_empires[#all_empires+1] = blank
  local empire = all_empires[#all_empires]._ref 
  planet.empire=empire
  add_planet(planet,empire)

  SCOPE.SETUP_ENV.setup_splinter_leader(planet.empire,planet)

  --blank.leader = copy | get_splinter_leader(species)


  local empire in planet

  empire.scientist = copy | get_default_scientist(species)


  init_empire_tech(empire)
  order.grant_all_techs(empire,initial_monster_tech)

  return planet.empire
end
To:

Code: Select all

local function new_minor_empire(species,planet)

  local count=0

  for i,empire in pairs | all_empires

    if empire.minor_faction==species
      count++
    end

  end

   local blank = blank_empire( 
    format("%s_minor_%d",species,count+1),  -- this should be replaced by setup_splinter_leader()
    --format('Independent (%s)',capitalize | species),
    species,'cyan')

  blank.spl_economy=true     
  blank.minor_faction=species


  all_empires[#all_empires+1] = blank
  local empire = all_empires[#all_empires]._ref 
  planet.empire=empire
  add_planet(planet,empire)

  SCOPE.SETUP_ENV.setup_splinter_leader(planet.empire,planet)

  --blank.leader = copy | get_splinter_leader(species)


  local empire in planet

  empire.scientist = copy | get_default_scientist(species)


  init_empire_tech(empire)
  order.grant_all_techs(empire,initial_monster_tech)

  return planet.empire
end



In Lua state\Orders\colonization.lua

To prevent splinter colonies from colonizing add

Code: Select all

	if empire.spl_economy
		return false
	end
Which means:
Change:

Code: Select all

function Empire.could_colonize(empire,planet)
	 local type,size in planet!

	if size=='Tiny'
		return false
 	end

	 if easy_planet_colonization_type(empire!.species,type)
		 return true
	 end

	if type=='Gas Giant' return false end
	if type=='WarpNode' return false end

	return empire:known 'Habitat Domes' 
end

function Empire.can_colonize(empire,planet)


	if planet.empire
    -- we can colonize our own outposts, but otherwise, planets
    -- already belonging to an empire can never be colonized
    if not( (planet.empire==empire) and planet.no_colony )
      return
    end
  end

	return empire : could_colonize(planet)
end
To:

Code: Select all

function Empire.could_colonize(empire,planet)
	 local type,size in planet!

	if size=='Tiny'
		return false
 	end

	 if easy_planet_colonization_type(empire!.species,type)
		 return true
	 end

	if type=='Gas Giant' return false end
	if type=='WarpNode' return false end

	return empire:known 'Habitat Domes' 
end

function Empire.can_colonize(empire,planet)


	if planet.empire
    -- we can colonize our own outposts, but otherwise, planets
    -- already belonging to an empire can never be colonized
    if not( (planet.empire==empire) and planet.no_colony )
      return
    end
  end

	return empire : could_colonize(planet)
end



In Lua state\Galaxy\apply_morale_effects.lua

To prevent assimilation of human refugees when they are not in a major empire yet add:

Code: Select all

if planet.empire.spl_economy
      converts=0
    end
Change:

Code: Select all

function suffix_morale_effects.refugee(planet,race,morale)
  local chance = saturate( (morale-10)/40 )*.3 + .1
  if chance > 0 

    local converts = min(
      planet.pop[race],
      bernoulli_trials(ceil(planet.pop[race]), chance) )



    if converts > 0
      local vanilla0 = planet.pop[remove_race_suffix | race] 
      order.convert_to_vanilla(planet,race,converts)

      if (not vanilla0) or (not planet.pop[race])
        order.add_report {
          ..planet.empire,
          type = 'refugees_assimilated',
          ..planet,
          ..converts,
          ..race,
          ..vanilla0,
        }
      end

      
      if (planet.empire==gui_player()) and (not planet.pop[race])
        mark_achievement 'ACH_REFUGEE_ASSIMILATE'
      end

    end
  end
end
To:

Code: Select all

function suffix_morale_effects.refugee(planet,race,morale)
  local chance = saturate( (morale-10)/40 )*.3 + .1
  if chance > 0 

    local converts = min(
      planet.pop[race],
      bernoulli_trials(ceil(planet.pop[race]), chance) )



    if planet.empire.spl_economy
      converts=0
    end
    if converts > 0
      local vanilla0 = planet.pop[remove_race_suffix | race] 
      order.convert_to_vanilla(planet,race,converts)

      if (not vanilla0) or (not planet.pop[race])
        order.add_report {
          ..planet.empire,
          type = 'refugees_assimilated',
          ..planet,
          ..converts,
          ..race,
          ..vanilla0,
        }
      end

      
      if (planet.empire==gui_player()) and (not planet.pop[race])
        mark_achievement 'ACH_REFUGEE_ASSIMILATE'
      end

    end
  end
end



In Lua state\AI\MonsterAI.lua

The refugee colonies often spawn with pirate ships in the system which would now bombard your splinter colony as soon as the game starts, to prevent it add

Code: Select all

	-- never attack the spl
	if their_empire.spl_economy
		return
	end

	-- the spl never attacks
	if r.empire.spl_economy
		return
	end
Pirates and splinters should now coexist together. Lore-wise I would say they could have a deal with pirates where splinter colony gives up some of their resources for peace

So:
Change:

Code: Select all

function desire_attack(r)

  --print 'always attack'

  local their_empire,star in r

  -- don't attack people we're not at war with
  if not at_war(r.empire,their_empire)
    return
  end

	-- never attack the herald
	if their_empire.monster_faction=='arda'
		return
	end

	-- the herald never attacks
	if r.empire.monster_faction=='arda'
		return
	end

  --for i, instance in all_ongoing_events()
  for i,r2 in all_non_removed_reports()
  
    if ( r2.type=='diplo_encounter' ) and (r2.star==r.star) and (r2.their_empire==r.empire) and (not r2.resolved)
      print('ongoing diplo_encounter prempting normal AI handing!')
      return
    end


  end


	-- star harpies won't attack if there are no ships to harvest
	-- or if the empire in question has harpy repellant
	if r.empire.monster_faction=='space_harpies'
		if not has_military_fleet(their_empire,star)
			return
		end
		if star.type~='hsa' and their_empire:known 'Harpy Repellant'
			return
		end
	end

  
  if their_empire.stars[star]
  
    for i,planet in rpairs (star.planets,|) 
        function(p1,p2) return star.planets[p1].summed_pop > star.planets[p2].summed_pop end
      if planet.empire==their_empire
        return true,planet
      end
    end

    error "couldn't find a planet"
  end 

  --print(..star)


  return true

  --print('hi there')



end
To:

Code: Select all

function desire_attack(r)

  --print 'always attack'

  local their_empire,star in r

  -- don't attack people we're not at war with
  if not at_war(r.empire,their_empire)
    return
  end

	-- never attack the herald
	if their_empire.monster_faction=='arda'
		return
	end

	-- the herald never attacks
	if r.empire.monster_faction=='arda'
		return
	end

	-- never attack the spl
	if their_empire.spl_economy
		return
	end

	-- the spl never attacks
	if r.empire.spl_economy
		return
	end

  --for i, instance in all_ongoing_events()
  for i,r2 in all_non_removed_reports()
  
    if ( r2.type=='diplo_encounter' ) and (r2.star==r.star) and (r2.their_empire==r.empire) and (not r2.resolved)
      print('ongoing diplo_encounter prempting normal AI handing!')
      return
    end


  end


	-- star harpies won't attack if there are no ships to harvest
	-- or if the empire in question has harpy repellant
	if r.empire.monster_faction=='space_harpies'
		if not has_military_fleet(their_empire,star)
			return
		end
		if star.type~='hsa' and their_empire:known 'Harpy Repellant'
			return
		end
	end

  
  if their_empire.stars[star]
  
    for i,planet in rpairs (star.planets,|) 
        function(p1,p2) return star.planets[p1].summed_pop > star.planets[p2].summed_pop end
      if planet.empire==their_empire
        return true,planet
      end
    end

    error "couldn't find a planet"
  end 

  --print(..star)


  return true

  --print('hi there')



end


In Lua state\Orders\population.lua

To prevent system blockade by pirates add

Code: Select all

 or (empire.spl_economy and (their_empire.monster_faction=='pirate'))
Change:

Code: Select all

  function Empire.system_blockaded(empire,star)

		for _,their_empire in pairs(all_empires) do 
		
			if at_war(their_empire,empire) and 
				(not their_empire.system_defeats[star]) and
        their_empire: has_armed_ships(star)

				if not ( empire:known 'Harpy Repellant' and (their_empire.monster_faction=='space_harpies') )
					return true
				end

			end
		end 
  end
To:

Code: Select all

  function Empire.system_blockaded(empire,star)

		for _,their_empire in pairs(all_empires) do 
		
			if at_war(their_empire,empire) and 
				(not their_empire.system_defeats[star]) and
        their_empire: has_armed_ships(star)

				if not ( (empire:known 'Harpy Repellant' and (their_empire.monster_faction=='space_harpies')) or (empire.spl_economy and (their_empire.monster_faction=='pirate')) )
					return true
				end

			end
		end 
  end



In Lua state\Orders\raiders.lua

To exclude Splinters from being a raider target add

Code: Select all

or empire.spl_economy
Change:

Code: Select all

function neighboring_empires(raider_empire)
  local push, candidates = pusher {}
  local home_star = raider_empire!.monster_star

  for i,empire ; all_empires

    if not ( empire.monster_economy or empire.eliminated )

      local _TRACE_INFO = empire.name

      local closest,dist = get_min_key(empire.stars,|) function(star)
        return star_dist(star,home_star)
      end

      push {..empire, dist=dist or 1e30,..closest}

    end

  end

  table.sort(candidates,|)function(a,b) return a.dist<b.dist end

  if not next | candidates
    return _SAFE
  end

  --local max_dist = candidates[1].dist*1.2

  local max_dist = 1.5*raider_empire.drive_range


  local rval = {}

  for i,v ; candidates
    if v.dist <=max_dist
      rval[v.empire]=v.closest
    end 
  end

  --print(..max_dist)
  --print(v2s | candidates)
  --print(v2s | rval)

  return rval
end
To:

Code: Select all

function neighboring_empires(raider_empire)
  local push, candidates = pusher {}
  local home_star = raider_empire!.monster_star

  for i,empire ; all_empires

    if not ( empire.monster_economy or empire.eliminated or empire.spl_economy)

      local _TRACE_INFO = empire.name

      local closest,dist = get_min_key(empire.stars,|) function(star)
        return star_dist(star,home_star)
      end

      push {..empire, dist=dist or 1e30,..closest}

    end

  end

  table.sort(candidates,|)function(a,b) return a.dist<b.dist end

  if not next | candidates
    return _SAFE
  end

  --local max_dist = candidates[1].dist*1.2

  local max_dist = 1.5*raider_empire.drive_range


  local rval = {}

  for i,v ; candidates
    if v.dist <=max_dist
      rval[v.empire]=v.closest
    end 
  end

  --print(..max_dist)
  --print(v2s | candidates)
  --print(v2s | rval)

  return rval
end



In Lua state\Setup\special_decks.lua

To give splinters a reasonable start with one lab mine etc and another farm to prevent starvation (as they still don't build improvements)

Change:

Code: Select all

  decks.treasure.Arid = valid_special_deck {

    [ {'splinter', species='human', pop={human_refugee=2,}, farms=1 } ] = 2,
    [ {'splinter', species='haduir', pop={haduir=2,}, factories=1, farms=1 } ] = 1,

    derelict_colony_draw =2,
  }  

  decks.treasure.Glacier = valid_special_deck {
    [ {'splinter', species='human', pop={human_refugee=2,}, farms=1 } ] = 2,
    star_resource_draw =1,
    derelict_colony_draw =2,
  }

  decks.treasure.Garden = valid_special_deck {
    [ {'splinter', species='human', pop={human_refugee=2,}, factories=1 } ] = 2,
    [ {'splinter', species='teros', pop={teros=2,}, factories=1 } ] = 1,


    star_resource_draw =1,
    derelict_colony_draw =1,
  }
To:

Code: Select all

  decks.treasure.Arid = valid_special_deck {

    [ {'splinter', species='human', pop={human_refugee=2,}, factories=1, farms=2, labs=1, mines=1, markets=1 } ] = 2,
    [ {'splinter', species='haduir', pop={haduir=2,}, factories=1, farms=2, labs=1, mines=1, markets=1 } ] = 1,

    derelict_colony_draw =2,
  }  

  decks.treasure.Glacier = valid_special_deck {
    [ {'splinter', species='human', pop={human_refugee=2,}, factories=1, farms=2, labs=1, mines=1, markets=1 } ] = 2,
    star_resource_draw =1,
    derelict_colony_draw =2,
  }

  decks.treasure.Garden = valid_special_deck {
    [ {'splinter', species='human', pop={human_refugee=2,}, factories=1, farms=2, labs=1, mines=1, markets=1 } ] = 2,
    [ {'splinter', species='teros', pop={teros=2,}, factories=1, farms=2, labs=1, mines=1, markets=1 } ] = 1,


    star_resource_draw =1,
    derelict_colony_draw =1,
  }



In Lua state\Orders\encounters\splinter_colony.lua

To reduce the chance you can annex them without any effort now as they are more meaningful, set

Code: Select all

  local positive_chance = their_empire : calc_reputation(empire) / 50 
Instead of /30

Change:

Code: Select all

function callbacks.on_searched()

  --TODO! make this make some kind of sense.

  local planet,empire,special in SCOPE.encounter_info!
  if empire.monster_faction
    return
  end
  local encounter = 'splinter'
  local their_empire=planet.empire
  local suffix = '_generic'

  empire.contactable_empires[their_empire]=true
  empire.known_empires[their_empire]=true
  their_empire.contactable_empires[empire]=true
  their_empire.known_empires[empire]=true


  if not their_empire.minor_faction
    -- looks like this is not the special we expected it to be
    -- lets just quitely clean that up.
    order.remove_special(special)
    return
  end


  local positive_chance = their_empire : calc_reputation(empire) / 30 


  for i, issue in ipairs | their_empire : get_issue_list(empire)
    if issue.liberate_case
      suffix='_liberate'
    end
  end


  positive_chance=min(.9, saturate (positive_chance) )

  local reaction = random_chance(positive_chance) and 'friendly' or 'hostile'
  local can_annex = reaction == 'friendly'

  if (reaction=='friendly') and group_species[their_empire.species]==group_species[empire.species]
    suffix='_splinter'
  end


  if reaction=='hostile' and suffix=='_liberate'
    if random_chance(.5)
      reaction='neutral'
    end
  end



  reaction..=suffix


   order.add_report {
    type='settlement_encounter',
    ..encounter,
    dialog_tree = {reaction},
    star=planet.star,
    ..empire,
    ..special,
    ..planet,
    ..can_annex,
    their_empire=planet.empire,

  } 

end
To:

Code: Select all

function callbacks.on_searched()

  --TODO! make this make some kind of sense.

  local planet,empire,special in SCOPE.encounter_info!
  if empire.monster_faction
    return
  end
  local encounter = 'splinter'
  local their_empire=planet.empire
  local suffix = '_generic'

  empire.contactable_empires[their_empire]=true
  empire.known_empires[their_empire]=true
  their_empire.contactable_empires[empire]=true
  their_empire.known_empires[empire]=true


  if not their_empire.minor_faction
    -- looks like this is not the special we expected it to be
    -- lets just quitely clean that up.
    order.remove_special(special)
    return
  end


  local positive_chance = their_empire : calc_reputation(empire) / 50 


  for i, issue in ipairs | their_empire : get_issue_list(empire)
    if issue.liberate_case
      suffix='_liberate'
    end
  end


  positive_chance=min(.9, saturate (positive_chance) )

  local reaction = random_chance(positive_chance) and 'friendly' or 'hostile'
  local can_annex = reaction == 'friendly'

  if (reaction=='friendly') and group_species[their_empire.species]==group_species[empire.species]
    suffix='_splinter'
  end


  if reaction=='hostile' and suffix=='_liberate'
    if random_chance(.5)
      reaction='neutral'
    end
  end



  reaction..=suffix


   order.add_report {
    type='settlement_encounter',
    ..encounter,
    dialog_tree = {reaction},
    star=planet.star,
    ..empire,
    ..special,
    ..planet,
    ..can_annex,
    their_empire=planet.empire,

  } 

end



And that should be it!

Early game should now be a little more engaging when it comes to diplomacy and fighting