7Soul

C3 Pilgrim's Bastion script

Jul 2nd, 2024
978
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 8.28 KB | Source Code | 0 0
  1. import mmap
  2. import math
  3. import sys, getopt
  4.  
  5. our_city = "Tingis"
  6.  
  7. terrain_offset = 0x2009B
  8.  
  9. def writeLong(value, len):
  10.     return (value).to_bytes(len,byteorder='little')
  11.  
  12. def writeShort(value, len):
  13.     return (value).to_bytes(len,byteorder='big')
  14.  
  15. def getQuotaOffset(city, good):
  16.     offset = partners_offset + (partners[city] * 0x40) + (goods[good] * 0x04)
  17.     return offset
  18.    
  19. def getCityOffset(city):
  20.     offset = cities_offset + 0x03 # city name id
  21.     # Check if we found the city, since they aren't in order
  22.     for i in range(28): # 0 to 27
  23.         offset += 66
  24.         mm.seek(offset)
  25.         if mm.read_byte() == cities[city]:
  26.             break
  27.        
  28.     ## then add 6 to get to buy flags (16 bytes) and then sell flags
  29.     return offset
  30.    
  31. def setTradeRoutePrice(city, price):
  32.     offset = getCityOffset(city) - 0x03 + 0x26
  33.     mm.seek(offset)
  34.     mm.write( writeLong(price, 2) )
  35.    
  36. def changeGoodsPrices(good, multi, type):
  37.     # Type 0 = both, 1 = only buyers, 2 = only sellers
  38.     offset = 0x125C3C
  39.     mm.seek(offset)
  40.     mm.seek(goods[good] * 0x08, 1)
  41.     for i in range(2):
  42.         if i == 0 and type == "sellers":
  43.             mm.seek(4,1)
  44.             continue
  45.         if i == 1 and type == "buyers":
  46.             continue
  47.         price = math.floor(int(mm.read_byte()) * multi)
  48.         mm.seek(-1,1)
  49.         mm.write( writeLong(price, 4) )
  50.         # print(mm.read_byte())
  51.        
  52. def setLocalProduction(good, value):
  53.     offset = getCityOffset(our_city) # cur byte is after city name
  54.     mm.seek(2 + 16, 1)
  55.     mm.seek(goods[good], 1)
  56.     mm.write_byte(value)
  57.  
  58. with open("D:\Games\Caesar 3 Julius\Test.c3u", "r+b") as f:
  59.     # memory-map the file, size 0 means whole file
  60.     mm = mmap.mmap(f.fileno(), 0)
  61.    
  62.     goods = {
  63.         "wheat":      0x01,
  64.         "vegetables": 0x02,
  65.         "fruits":     0x03,
  66.         "olives":     0x04,
  67.         "vines":      0x05,
  68.         "meat":       0x06,
  69.         "wine":       0x07,
  70.         "oil":        0x08,
  71.         "iron":       0x09,
  72.         "timber":     0x0A,
  73.         "clay":       0x0B,
  74.         "marble":     0x0C,
  75.         "weapons":    0x0D,
  76.         "furniture":  0x0E,
  77.         "pottery":    0x0F,
  78.     }
  79.    
  80.     partners_offset = 0x131702
  81.     partners = {
  82.         "Carthago Nova"  : 0x01,
  83.         "Caesarea"  : 0x02,
  84.         "Volubilis" : 0x03,
  85.         "Valentia"  : 0x04,
  86.         "Tarraco"   : 0x05,
  87.     }
  88.    
  89.     cities_offset = 0x12516C
  90.     cities = {
  91.         "Roma" : 0x00,
  92.         "Tarentum" : 0x01,
  93.         "Capua" : 0x02,
  94.         "Brundisium" : 0x03,
  95.         "Mediolanum" : 0x04,
  96.         "Carthago Nova" : 0x05,
  97.         "Carthago" : 0x06,
  98.         "Tarraco" : 0x07,
  99.         "Athenae" : 0x08,
  100.         "Pergamum" : 0x09,
  101.         "Syracusae" : 0x0A,
  102.         "Toletum" : 0x0B,
  103.         "Tarsus" : 0x0C,
  104.         "Leptis Magna" : 0x0D,
  105.         "Tingis" : 0x0E,
  106.         "Corinthus" : 0x0F,
  107.         "Valentia" : 0x10,
  108.         "Lindum" : 0x19,
  109.         "Calleva" : 0x1A,
  110.         "Lutetia" : 0x1B,
  111.         "Caesarea" : 0x1F,
  112.         "Augusta Trevorum" : 0x21,
  113.         "Volubilis" : 0x23,
  114.         "Londinium" : 0x24,
  115.     }
  116.    
  117.     buildings = {
  118.         "farms" : 1,
  119.     }
  120.    
  121.     opts, args = getopt.getopt(sys.argv[1:],"wf")
  122.      
  123.     for opt, arg in opts:
  124.         if opt in ['-w']:
  125.             print("warehouse only")
  126.             # Erase cliff tiles
  127.             eraseTiles = [0x24593, 0x26B37, 0x26317, 0x25F49, 0x28C0F, 0x29BD7]
  128.             for pos in eraseTiles:
  129.                 mm.seek(pos)
  130.                 mm.write_byte(0x00)
  131.        
  132.             # Add marble to warehouse
  133.             warehouse = 0xE695A
  134.             mm.seek(warehouse)
  135.             mm.seek(0x0C,1)
  136.             mm.write_byte(0x0C)
  137.             mm.seek(warehouse)
  138.             mm.seek(0x34,1)
  139.             mm.write_byte(0x0C) # 12 marble in 1 tile why not
  140.            
  141.             # This replaces ramps with roads. Basically instead of a ramp being a 2x2 road, it becomes a 1x2 road
  142.             rampscount = 0
  143.             ramps = []
  144.             mm.seek(terrain_offset) #2009B
  145.             # elevation: 59b40
  146.             rampBot = "0004"
  147.             rampsBot = "00040004"
  148.             rampTop = "0006"
  149.             rampsTop = "00060006"
  150.                        
  151.             mm.seek(terrain_offset-1)
  152.             for i in range(int(162*162*2)):
  153.                 byte = mm.read(4)
  154.                 # find      bottom of stairs - bottom of stairs
  155.                 # turn into road - empty
  156.                 if byte.hex() == rampsBot:
  157.                     # print(byte)
  158.                     mm.seek(-4,1)
  159.                     # bytes have to be written swapped
  160.                     mm.write_byte(0x40)
  161.                     mm.write_byte(0x00)
  162.                     mm.write_byte(0x00)
  163.                     mm.write_byte(0x00)
  164.                     print(terrain_offset + (i*2))
  165.                     rampscount += 1
  166.                     print("ramp")
  167.                 mm.seek(-2,1)
  168.             print(rampscount)
  169.            
  170.             mm.seek(terrain_offset-1)
  171.             for i in range(int(162*162*2)):
  172.                 byte = mm.read(4)
  173.                 # find      top of stairs - top of stairs
  174.                 # turn into road w/elevation - elevation
  175.                 if byte.hex() == rampsTop:
  176.                     mm.seek(-4,1)
  177.                     # bytes have to be written swapped
  178.                     mm.write_byte(0x40)
  179.                     mm.write_byte(0x02)
  180.                     mm.write_byte(0x00)
  181.                     mm.write_byte(0x02)
  182.                     print(terrain_offset + (i*2))
  183.                     print("ramp elevated")
  184.                 mm.seek(-2,1)
  185.                
  186.             mm.seek(terrain_offset-1)
  187.             for i in range(int(162*162*2)):
  188.                 byte = mm.read(4)
  189.                 # find      bottom of stairs - top of stairs
  190.                 # turn into road w/elevation - elevation
  191.                 if byte.hex() == "00040006":
  192.                     mm.seek(-4,1)
  193.                     mm.seek(324,1)
  194.                     byte = mm.read(2)
  195.                     # if the tile on the next row is also a ramp, this tile becomes just a hill
  196.                     if byte.hex() == rampBot or byte.hex() == rampTop:
  197.                         mm.seek(-2,1)
  198.                         mm.seek(-324,1)
  199.                         # bytes have to be written swapped
  200.                         mm.write_byte(0x00)
  201.                         mm.write_byte(0x00)
  202.                         mm.write_byte(0x00)
  203.                         mm.write_byte(0x02)
  204.                         print("ramp low to high with other piece of ramp in next row")
  205.                     else:
  206.                         mm.seek(-2,1)
  207.                         mm.seek(-324,1)
  208.                         # bytes have to be written swapped
  209.                         mm.write_byte(0x40)
  210.                         mm.write_byte(0x00)
  211.                         mm.write_byte(0x40)
  212.                         mm.write_byte(0x02)
  213.                         print("ramp low to high with nothing next row")
  214.                 mm.seek(-2,1)
  215.                
  216.             mm.seek(terrain_offset-1)
  217.             for i in range(int(162*162*2)):
  218.                 byte = mm.read(4)
  219.                 if byte.hex() == "00060004":
  220.                     mm.seek(-4,1)
  221.                     mm.seek(324,1)
  222.                     byte = mm.read(2)
  223.                     # if the tile on the next row is also a ramp, this tile becomes just a hill
  224.                     if byte.hex() == rampTop or byte.hex() == rampBot:
  225.                         mm.seek(-2,1)
  226.                         mm.seek(-324,1)
  227.                         # bytes have to be written swapped
  228.                         mm.write_byte(0x40)
  229.                         mm.write_byte(0x02)
  230.                         mm.write_byte(0x40)
  231.                         mm.write_byte(0x00)
  232.                         print("ramp high to low with other piece of ramp in next row")
  233.                     else:
  234.                         mm.seek(-2,1)
  235.                         mm.seek(-324,1)
  236.                         # bytes have to be written swapped
  237.                         mm.write_byte(0x00)
  238.                         mm.write_byte(0x02)
  239.                         mm.write_byte(0x00)
  240.                         mm.write_byte(0x00)
  241.                         print("ramp high to low with nothing next row")
  242.                 mm.seek(-2,1)
  243.                
  244.            
  245.                
  246.             # print("found %d ramps" % rampscount)
  247.         if opt == '-f':
  248.             print("finish")
  249.            
  250.             # Reset money to 5k
  251.             mm.seek(0xE218C)
  252.             mm.write_byte(0x88)
  253.             mm.write_byte(0x13)
  254.             mm.seek(0xE4CFC)
  255.             mm.write_byte(0x88)
  256.             mm.write_byte(0x13)
  257.            
  258.             # Disable buildings
  259.             mm.seek(0x126342) # Fort
  260.             mm.write_byte(0x00)
  261.             mm.seek(0x12634A) # Large Temple
  262.             mm.write_byte(0x00)
  263.            
  264.             # Burn Mars large temple (build first after warehouse)
  265.             mm.seek(0xE6D5B)
  266.             mm.seek(0x3F, 1)
  267.             mm.write_byte(0x64) # 100 fire rate
  268.            
  269.             # Sets the next 5 buildings to never burn or collapse
  270.             mm.seek(0xE6D5A)
  271.             mm.seek(0x44, 1)
  272.             for n in range(5):
  273.                 mm.seek(0x80, 1)
  274.                 mm.write_byte(0x01)
  275.                 mm.seek(-1, 1)
  276.            
  277.             # Change favor to 35
  278.             mm.seek(0xE6314)
  279.             mm.write_byte(35)
  280.            
  281.             # Change savings to 1500
  282.             mm.seek(0xE6450)
  283.             mm.write_byte(0xDC)
  284.             mm.write_byte(0x05)
  285.            
  286.             # Makes all goods 20% less profitable
  287.             for g, h in goods.items():
  288.                 changeGoodsPrices(g, 1.0 + 0.20, "buyers")
  289.                 changeGoodsPrices(g, 1.0 - 0.20, "sellers")
  290.    
  291.    
  292.    
  293.     # Remove unwanted quotas
  294.     mm.seek(getQuotaOffset("Caesarea", "marble"))
  295.     mm.write_byte(0x00)
  296.     mm.seek(getQuotaOffset("Carthago Nova", "timber"))
  297.     mm.write_byte(0x00)
  298.     mm.seek(getQuotaOffset("Valentia", "timber"))
  299.     mm.write_byte(0x00)
  300.     mm.seek(getQuotaOffset("Tarraco", "timber"))
  301.     mm.write_byte(0x00)
  302.     mm.seek(getQuotaOffset("Volubilis", "iron"))
  303.     mm.write_byte(0x0F)
  304.    
  305.     # changeGoodsPrices("vegetables", 1.20, "both")
  306.     # changeGoodsPrices("iron", 0.875, "both")
  307.     # changeGoodsPrices("pottery", 0.85, "both")
  308.     # changeGoodsPrices("marble", 1.20, "both")
  309.     # changeGoodsPrices("furniture", 0.75, "both")
  310.     # changeGoodsPrices("timber", 0.5, "sellers")
  311.    
  312.    
  313.    
  314.     setTradeRoutePrice("Carthago Nova", 2100)
  315.     setTradeRoutePrice("Caesarea", 800)
  316.     setTradeRoutePrice("Volubilis", 2000)
  317.     setTradeRoutePrice("Valentia", 900)
  318.     setTradeRoutePrice("Tarraco", 2500)
  319.    
  320.     setLocalProduction("timber", 1)
  321.    
  322.     # close the map
  323.     mm.close()
  324.    
Advertisement
Add Comment
Please, Sign In to add comment