I have just finished a version of this game which will work with the current version. It is in Python, so if you don't have either Python or the Python libraries (2.6.4), you will need one of those. When the most recent file is run from the raws folder using Python, it will add an insect body type to body_default.txt, and creates a new raw called creature_gigantic.txt. It does its best to exclude inapropriate creatures such as civable races, but it may not necessarily exclude creatures from any mods you have. If it makes something you don't like, just remove it from the raws or rerun it.One reason many people, including myself, have found
The Ark Project exciting was the presumption that the next version would randomly select some creatures to become giant semi-megabeasts, and there plethora of creature raws from the Ark Project would make this feature even more interesting. Unfortunately, Toady has revealed that this will not be the case. However, I am now undertaking a project to write a program which will add the feature to the game. My plan is to write the program in Python to help teach myself the language, and release the application and its source code, hopefully bundled with the Ark raws. The program will compile a list of each mundane creature and its raw file, select a certain number of creatures at random, and produce a new set of raws with added modified giant semi-megabeast versions of the selected creatures.
I would also like for this mod to identify categories of creatures (defined by common associations) and add special abilities to the megabeasts based on the associations we have with the base creatures. One purpose of this thread is to discuss potential categories and abilities, though this will remain in the brainstorming phase until the Ark Project is complete. Here are some examples, with a possible prefix/suffix for the megabeast's name, the likelihood for the variation to occur, and a brief description for each entry:
- Fire breathing: for desert creatures?
- Armored: extra hard hide/scales/plates for turtles, armadillos, and other armored animals
- Terrifying: creatures known for their loud roars could emit a poison gas called 'terrifying roar' which causes fear
- Spiny: porcupines and other spiny/quilled creatures could emit a poison gas called 'flurry of quills' which causes pain
- Plague bearing: until diseases are added to the game, this will have to be in the form of a long lasting poison spread by megabeast insect bites
- of the Swarm: some colony-based insects could become a large (bear sized) version that spawns in massive numbers, rather than a giant megabeast
- Rampaging: most megabeasts should get this tag...maybe termtes and some ants could become a 'dread swarm' with buildingdestroyer, but I'm not sure how to make a megabeast out of a cloud of insects
- Bejeweled: nocturnal animals may have eyes made of gems, and anything with scales could have gems in their scales
- Thoughtful: primates and some others could have [can_learn]
- Tribal: all creatures could qualify for a chance to be a large non-megabeast with [can_learn] and the animal person template
I just finished a simple version of this that works with the current version. When placed in the raw folder, it will ask you how many gigantic creatures you want, and it will randomly choose a creature (excluding subterranean, standard, fanciful, megabeasts, water creatures, and repeats), and gives it standard modifications, and removes un-megabeasty tags. Vermin are given bodies and attacks, and the program adds an insect body to bodies_default.txt. The results are placed in creature_gigantic.txt.
Here is the code, in case anyone with a fair knowledge of Python wants to look at it. It is not very efficient, but does everything fine:
#get the directory name and list creature raw files
howmany = input('How many creatures would you like?')
import os
import dircache
import random
import re
current = os.getcwd() #current directory
rawlist = dircache.listdir(os.getcwd()) #list of all files in directory
creaturerawlist=[] #list of all creature raw files. I still have to figure out how to exclude non-ark files...
newcreaturerawlist=[] #list of creature files, each being a list of creature raws
for raw in rawlist:
if raw[:9]=='creature_' and raw[9:] != 'gigantic.txt' and raw[9:] != 'equipment.txt' and raw[9:] != 'subterranean.txt' and raw[9:] != 'standard.txt' and 'river' not in raw and 'lake' not in raw and 'ocean' not in raw:
if raw[9:] != 'gigantic' and raw[9:] != 'fanciful':
creaturerawlist = creaturerawlist + [raw]
#take each creature raw file listed in creaturerawlist, and replace it with a list of every creature therein and its raws
for rawfile in creaturerawlist:
#select a file and store it as 'creatureraws'
slash = '\\'
filetoget = current + slash + rawfile
openfile = open(filetoget,'r')
creatureraws = openfile.read()
newlist = [] #a temporary list of creature raws for an individual file
#remove the header of the raw for later use
where = creatureraws.find('[CREATURE:')
newlist = newlist + [creatureraws[:where]]
creatureraws = creatureraws[where:]
where = 1 + creatureraws[1:].find('[CREATURE:')
#divide the .txt file into a list of creatures with their raws named new
while where > 0:
newlist = newlist + [creatureraws[:where]]
creatureraws = creatureraws[where:]
where = 1 + creatureraws[1:].find('[CREATURE:')
newlist = newlist + [creatureraws]
newcreaturerawlist = newcreaturerawlist + [newlist]
#remove megabeasts and semimegabeasts and civable races, just in case. For some reason, this is missing bronze collosuses, minotaurs, and cyclopses
for rawfile in newcreaturerawlist:
for raw in rawfile:
if '[MEGABEAST]' in raw or '[SEMIMEGABEAST]' in raw or '[CAN_CIV]' in raw or '[INTELLIGENT]' in raw:
rawfile.remove(raw)
#list each creature for ease of reading
list = []
for raws in newcreaturerawlist:
templist = []
for creature in raws:
where = creature.find(']')
templist = templist + [creature[10:where]]
list = list + [templist]
randexport = ""
#Create/overwrite the gigantic creature raw file
FILE=current + '\\creature_gigantic.txt'
f=open(FILE,'w')
f.write('creature_gigantic\n\n[OBJECT:CREATURE]\n\n')
f.close()
#add an insect body to body_default.txt. does not play well with body_default files which already have insect entries.
FILE=current + '\\body_default.txt'
f=open(FILE,'r')
if '[BODY:INSECT]' not in f.read():
f.close()
f=open(FILE,'a')
f.write('\n\n[BODY:INSECT]\n[BP:UB:cephalothorax][HEAD][UPPERBODY]\n[BP:LB:abdomen][CON:UB][LOWERBODY]\n[BP:RA1:right first leg][CON:UB][liMB][RIGHT]\n[BP:LA1:left first leg][CON:UB][liMB][LEFT]\n[BP:RF1:right first foot][CON:RA1][STANCE][RIGHT]\n[BP:LF1:left first foot][CON:LA1][STANCE][LEFT]\n[BP:RA2:right second leg][CON:UB][liMB][RIGHT]\n[BP:LA2:left second leg][CON:UB][liMB][LEFT]\n[BP:RF2:right second foot][CON:RA2][STANCE][RIGHT]\n[BP:LF2:left second foot][CON:LA2][STANCE][LEFT]\n[BP:RA3:right third leg][CON:UB][liMB][RIGHT]\n[BP:LA3:left third leg][CON:UB][liMB][LEFT]\n[BP:RF3:right third foot][CON:RA3][STANCE][RIGHT]\n[BP:LF3:left third foot][CON:LA3][STANCE][LEFT]\n\n')
f.close()
#function designed to append a tag after the last tag in a raw file.
def Appendtag(tag,raw):
where = raw.find(re.findall(r'\][\n\t ]*$',raw)[0])
newraw = raw[:where] + ']\n\t' + tag + raw[where+1:]
return newraw
#select a random creature .txt, and a random creature from that .txt, find [SIZE:XX] and change it to 100. If there is not [SIZE:XX], it finds another file.
def Randomraw():
done = 0
while True and done != 1:
#choose a random raw in a random list, excluding the headers
randomcreaturesource = random.choice(newcreaturerawlist)
randomcreatureraw = random.choice(randomcreaturesource[1:])
header = re.findall(r'creature_[a-z -_]*\n',randomcreaturesource[0])[0][9:-1]
#if it is a vermin, remove vermin tags and add size, body, and attacks
if 'VERMIN' in randomcreatureraw:
if '[VERMIN_GROUNDER]' in randomcreatureraw:
randomcreatureraw=randomcreatureraw.replace('[VERMIN_GROUNDER]','')
if '[VERMIN_NOTRAP]' in randomcreatureraw:
randomcreatureraw=randomcreatureraw.replace('[VERMIN_NOTRAP]','')
if '[VERMIN_EATER]' in randomcreatureraw:
randomcreatureraw=randomcreatureraw.replace('[VERMIN_EATER]','')
if '[VERMIN_HATEABLE]' in randomcreatureraw:
randomcreatureraw=randomcreatureraw.replace('[VERMIN_HATEABLE]','')
if '[VERMIN_FISH]' in randomcreatureraw:
randomcreatureraw=randomcreatureraw.replace('[VERMIN_FISH]','')
if '[VERMIN_ROTTER]' in randomcreatureraw:
randomcreatureraw=randomcreatureraw.replace('[VERMIN_ROTTER]','')
if '[VERMIN_MICRO]' in randomcreatureraw:
randomcreatureraw=randomcreatureraw.replace('[VERMIN_MICRO]','')
randomcreatureraw=Appendtag('[SIZE:1]',randomcreatureraw)
#add [ATTACKS]
randomcreatureraw=Appendtag('[ATTACK:MAIN:BYTYPE:MOUTH:bite:bites:1:6:GORE][ATTACKFLAG_CANLATCH]',randomcreatureraw)
#add [BODY] according to the category of creature
if header == 'annelids':
randomcreatureraw=Appendtag('[BODY:TAIL:2EYES:NOSE:2LUNGS:HEART:GUTS:ORGANS:SPINE:BRAIN:MOUTH]',randomcreatureraw)
elif header == 'birds':
randomcreatureraw=Appendtag('[BODY:HUMANOID_FLIER:2EYES:2EARS:NOSE:2LUNGS:HEART:GUTS:ORGANS:THROAT:NECK:SPINE:BRAIN:MOUTH]',randomcreatureraw)
elif header == 'small_ocean' or randomcreaturesource[9:] == 'small_riverlake' or randomcreaturesource[9:] == 'large_ocean' or randomcreaturesource[9:] == 'large_riverlake': #unfortunately, categories like this give oysters fins...
randomcreatureraw=Appendtag('[BODY:BASIC_2PARTBODY:BASIC_HEAD:SIDE_FINS:DORSAL_FIN:TAIL:2EYES:HEART:GUTS:ORGANS:NECK:SPINE:BRAIN:MOUTH]',randomcreatureraw)
elif header == 'insects':
randomcreatureraw = Appendtag('[CHITIN]',randomcreatureraw)
randomcreatureraw=Appendtag('[BODY:INSECT:2EYES:HEART:GUTS:BRAIN:MOUTH]',randomcreatureraw)
else:
randomcreatureraw=Appendtag('[BODY:QUADRUPED:TAIL:2EYES:2EARS:NOSE:2LUNGS:HEART:GUTS:ORGANS:THROAT:NECK:SPINE:BRAIN:MOUTH]',randomcreatureraw)
#remove [NOT_BUTCHERABLE]
if randomcreatureraw.count('[NOT_BUTCHERABLE]') > 0:
randomcreatureraw = randomcreatureraw.replace('[NOT_BUTCHERABLE]','')
#check to make sure that the entry has a [SIZE] tag (and therefore is not fanciful)
if '[SIZE:' in randomcreatureraw and randomcreatureraw.count('[EVIL]') == 0 and randomcreatureraw.count('[GOOD]') == 0:
print re.findall(r'\[CREATURE:[A-Z _0-9-]*\]',randomcreatureraw)[0]
size = re.findall(r'SIZE:[0-9]*',randomcreatureraw)[0]
randomcreatureraw = randomcreatureraw.replace(size,'SIZE:20') #search for [SIZE:XX] and change it to 100
#change the name strings to say gigantic
alreadygiant = 0
namestring = re.findall(r'\[\NAME:[a-z \-\']+:[a-z \-\']+:[a-z \-\']+\]',randomcreatureraw)[0]
if re.findall(r'CREATURE:[A-Z _0-9-]*',randomcreatureraw)[0][-5:]=='GIANT':
randomcreatureraw = randomcreatureraw.replace(re.findall(r'CREATURE:[A-Z _0-9-]*',randomcreatureraw)[0][9:],re.findall(r'CREATURE:[A-Z _0-9-]*',randomcreatureraw)[0][9:-5] + 'GIGANTIC') #add _GIANT to the creature title, should make conditions for creatures with giant already in their name
namestringnew = namestring.replace('giant','gigantic')
alreadygiant = 1
else:
randomcreatureraw = randomcreatureraw.replace(re.findall(r'CREATURE:[A-Z _0-9-]*',randomcreatureraw)[0][9:],re.findall(r'CREATURE:[A-Z _0-9-]*',randomcreatureraw)[0][9:] + '_GIGANTIC')
namestringnew = namestring.replace(':',':gigantic ')
randomcreatureraw = randomcreatureraw.replace(namestring,namestringnew)
#change [CHILDNAME: if it is there
if '[CHILDNAME:' in randomcreatureraw:
childnamestring = re.findall(r'\[\CHILDNAME:[a-z \-\']+:[a-z \-\']+\]',randomcreatureraw)[0]
if alreadygiant == 1:
childnamestringnew = childnamestring.replace('giant','gigiantic')
else:
childnamestringnew = childnamestring.replace(':',':gigantic ')
randomcreatureraw = randomcreatureraw.replace(childnamestring,childnamestringnew)
#add prefstrings befitting the new creature's size
randomcreatureraw = Appendtag('[PREFSTRING:massive size]',randomcreatureraw)
#Make [PETVALUE] 5000
if randomcreatureraw.count('[PETVALUE:') > 0:
Petvalue = re.findall(r'\[PETVALUE:[0-9-]*',randomcreatureraw)[0][10:]
randomcreatureraw = randomcreatureraw.replace('[PETVALUE:'+Petvalue+']','[PETVALUE:5000]')
else:
randomcreatureraw = Appendtag('[PETVALUE:5000]',randomcreatureraw)
#Make [EXTRACT_VALUE] and [CHEESE_VALUE] 100 times as valuable
if randomcreatureraw.count('[EXCTRACT_VALUE:') > 0:
Extractvalue = re.findall(r'\[EXTRACT_VALUE:[0-9-]*',randomcreatureraw)[0]
randomcreatureraw = randomcreatureraw.replace(Extractvalue,Extractvalue + '00')
if randomcreatureraw.count('[CHEESE_VALUE:') > 0:
Extractvalue = re.findall(r'\[CHEESE_VALUE:[0-9-]*',randomcreatureraw)[0]
randomcreatureraw = randomcreatureraw.replace(Extractvalue,Extractvalue + '00')
#Make high [MODVALUE:20] and [FAT:10]
if randomcreatureraw.count('[MODVALUE:') > 0:
Modvalue = re.findall(r'\[MODVALUE:[0-9]*\]',randomcreatureraw)[0]
randomcreatureraw = randomcreatureraw.replace(Modvalue,'[MODVALUE:20]')
else:
randomcreatureraw = Appendtag('[MODVALUE:20]',randomcreatureraw)
if randomcreatureraw.count('[FAT:') > 0:
Fat = re.findall(r'\[FAT:[0-9]*\]',randomcreatureraw)[0]
randomcreatureraw = randomcreatureraw.replace(Fat,'[FAT:10]')
#remove [MAXAGE]
if randomcreatureraw.count('[MAXAGE:') > 0:
Maxage = re.findall(r'\[MAXAGE:[0-9]*:[0-9]*\]',randomcreatureraw)[0]
randomcreatureraw = randomcreatureraw.replace(Maxage,'')
#remove [MUNDANE]
if randomcreatureraw.count('[MUNDANE]') > 0:
randomcreatureraw = randomcreatureraw.replace('[MUNDANE]','')
#remove [COMMON_DOMESTIC] [WAGON_PULLER] [PACK_ANIMAL]
if randomcreatureraw.count('[WAGON_PULLER]') > 0:
randomcreatureraw = randomcreatureraw.replace('[WAGON_PULLER]','')
if randomcreatureraw.count('[COMMON_DOMESTIC]') > 0:
randomcreatureraw = randomcreatureraw.replace('[COMMON_DOMESTIC]','')
if randomcreatureraw.count('[PACK_ANIMAL]') > 0:
randomcreatureraw = randomcreatureraw.replace('[PACK_ANIMAL]','')
#remove [SMALL_REMAINS]
if randomcreatureraw.count('[SMALL_REMAINS]') > 0:
randomcreatureraw = randomcreatureraw.replace('[SMALL_REMAINS]','')
#remove [POPULATION_NUMBER]
if randomcreatureraw.count('[POPULATION_NUMBER:') > 0:
randomcreatureraw = randomcreatureraw.replace(re.findall(r'\[POPULATION_NUMBER:\d*:\d*\]',randomcreatureraw)[0],'')
#remove [GNAWER]
if randomcreatureraw.count('[GNAWER:') > 0:
randomcreatureraw = randomcreatureraw.replace(re.findall(r'\[GNAWER:\D*\]',randomcreatureraw)[0],'')
#remove [DIFFICULTY]...I'm not sure if this is neccessary, but megabeasts don't have the tag, so I assume a difficulty is implied in the megabeast tag
if randomcreatureraw.count('[DIFFICULTY:') > 0:
randomcreatureraw = randomcreatureraw.replace(re.findall(r'\[DIFFICULTY:\d*\]',randomcreatureraw)[0],"")
#give/improve [DAMBLOCK]
if randomcreatureraw.count('[DAMBLOCK:') > 0:
Damblock = re.findall(r'\[DAMBLOCK:[0-9-]*',randomcreatureraw)[0][10:]
randomcreatureraw = randomcreatureraw.replace('[DAMBLOCK:'+Damblock+']','[DAMBLOCK:' + str(int(Damblock)+2) + ']')
else:
randomcreatureraw = Appendtag('[DAMBLOCK:2]',randomcreatureraw)
#for land creatures and pool creatures, delete all [BIOME: tags and replace with [BIOME:ANY_LAND]
Biomes = re.findall(r'\[BIOME:[A-Z _]*\]',randomcreatureraw)
water = 0
for biome in Biomes:
if 'OCEAN' in biome or 'RIVER' in biome or 'LAKE' in biome:
water = 1
if water == 0 or randomcreatureraw.count('[AMPHIBIOUS]') > 0 or randomcreatureraw.count('[BIOME:ANY_POOL]') > 0:
for biome in Biomes:
randomcreatureraw = randomcreatureraw.replace(biome,'')
randomcreatureraw = Appendtag('[BIOME:ANY_LAND]',randomcreatureraw)
#Add [MEGABEAST]
randomcreatureraw = Appendtag('[MEGABEAST]',randomcreatureraw)
#Add [FANCIFUL]
randomcreatureraw = Appendtag('[FANCIFUL]',randomcreatureraw)
#Add [PET_EXOTIC], remove [PET]
if randomcreatureraw.count('[PET]') > 0:
randomcreatureraw = randomcreatureraw.replace('[PET]','')
if randomcreatureraw.count('[PET_EXOTIC]') == 0:
randomcreatureraw = Appendtag('[PET_EXOTIC]',randomcreatureraw)
#remove cluster, or replace it for insects
if '[CLUSTER_NUMBER:' in randomcreatureraw:
cluster = re.findall(r'\[CLUSTER_NUMBER:\d*:\d*\]',randomcreatureraw)[0]
randomcreatureraw = randomcreatureraw.replace(cluster,'')
if re.findall(r'creature_[a-z -_]*\n',randomcreaturesource[0])[0][9:-1] == 'insects':
randomcreatureraw = Appendtag('[CLUSTER_NUMBER:10:20]',randomcreatureraw)
#Add [BUILDINGDESTROYER] if not there
if randomcreatureraw.count('[BUILDINGDESTROYER:') > 0:
randomcreatureraw = randomcreatureraw.replace(re.findall(r'\[BUILDINGDESTROYER:\d\]',randomcreatureraw)[0],'[BUILDINGDESTROYER:2]')
else:
randomcreatureraw = Appendtag('[BUILDINGDESTROYER:2]',randomcreatureraw)
#Make [GRASSTRAMPLE:50]
if randomcreatureraw.count('[GRASSTRAMPLE:') > 0:
randomcreatureraw = randomcreatureraw.replace(re.findall(r'\[GRASSTRAMPLE:[0-9]*\]',randomcreatureraw)[0],'[GRASSTRAMPLE:50]')
else:
randomcreatureraw = Appendtag('[GRASSTRAMPLE:50]',randomcreatureraw)
#Add [liKES_FIGHTING]
randomcreatureraw = Appendtag('[liKES_FIGHTING]',randomcreatureraw)
#add a line break to reset indentation
randomcreatureraw = randomcreatureraw + '\n\n'
#remove any double line breaks in the middle of the raw
randomcreatureraw = randomcreatureraw.replace('\n\t\n\t','\n\t')
randomcreatureraw = randomcreatureraw.replace('\n\n','\n')
#signal that the program completed properly, and assign a global variable. I had been using return, but for some reason that was returning None about half the time.
print 'done'
done=1
#globals()["randexport"] = randomcreatureraw
return randomcreatureraw
#this happens if there is no size tag (vermin). for now it looks for another until a non-vermin is found, but I should figure out whether a vermin can just be given size...and how vermin will be treated in the next version.
creaturelist = []
namelist = []
for i in range(howmany):
dinner = 0
while True and dinner != 1:
newcreature = Randomraw()
name = re.findall(r'\[CREATURE:[A-Z _0-9-]*\]',newcreature)[0]
if name not in namelist:
creaturelist = creaturelist + [newcreature]
namelist = namelist + [name]
dinner = 1
#for i in creaturelist:
# print re.findall(r'\[CREATURE:[A-Z _]*\]',i)[0]
for i in namelist:
print i
FILE=current + '\\creature_gigantic.txt'
f=open(FILE,'a')
for creature in creaturelist:
f.write(creature)
f.close()
print 'done'