Apply this bugfix and improvement patch with manual file replacement or manual file editing. This cannot be applied by the mod system. If you plan to use mods with this patch, apply this to the unmodded game, and if there is a 'backup' folder then before starting the game either delete the 'backup' folder or apply this to the 'backup' folder as well. Mansion.tscn fixed visibility issues by moving text input for Default Title higher in list move lines 9016-9017 to after 9003. moved text starts with: [connection signal="text_changed" from="MainScreen/mansion/selfinspect/defaultMasterNoun" to="." method="_on_defaultMasterNoun_text_changed"] enabled meta links in self description panel(v2) add line after 9014: [connection signal="meta_clicked" from="MainScreen/mansion/selfinspect/selflookspanel/selfdescript" to="MainScreen/slave_tab" method="_on_slavedescript_meta_clicked"] added button for setting body image for player character(v3b) add line after 9010: [connection signal="pressed" from="MainScreen/mansion/selfinspect/selfbody" to="." method="_on_selfbody_pressed"] changed stat, slave, and item tooltips to not block mouse events(v2c) add the following line after 8931, 8918, 8909, 8903, 8893, 8884, 8875, 8857, 8844, 8832, 8824, 8816: mouse_filter = 2 add the following line after 8803, 8788: mouse_filter = 1 added label and tooltips to "Mansion Settings" panel to clarify supply settings(v3b) adjusted position of "Supply keep" GUI and changed minimum to 0(v3b) add lines after 8371: [node name="Label2" type="Label" parent="mansionsettings/Panel/supplykeep"] margin_left = -30.0 margin_top = -30.0 margin_right = 69.0 margin_bottom = -10.0 text = "Market Job Settings" add line after 8367: hint_tooltip = "If enabled, market workers will attempt to buy supplies up to the amount above" add lines after 8359: hint_tooltip = "Market workers will attempt to sell any supplies over this amount" mouse_filter = 1 remove line 8350: min_value = 1.0 replace lines 8344-8347 with: margin_left = 680.0 margin_top = 140.0 margin_right = 796.0 margin_bottom = 174.0 hint_tooltip = "Market workers will attempt to sell any supplies over this amount" added label and tooltip to "Mansion Settings" panel to clarify food settings, renamed "Food purchase"(v3b) add lines after 8342: [node name="Label2" type="Label" parent="mansionsettings/Panel/foodbuy"] margin_left = -30.0 margin_top = -30.0 margin_right = 53.0 margin_bottom = -10.0 text = "Cooking Job Settings" replace line 8341 with: text = "Low food resupply" add line after 8338: hint_tooltip = "Amount of food purchased by the cook when mansion has less than 200 food" mouse_filter = 1 adjusted position of "Food purchase" GUI and changed minimum to 0(v3b) remove line 8328: min_value = 20.0 replace lines 8322-8325 with: margin_left = 680.0 margin_top = 60.0 margin_right = 796.0 margin_bottom = 94.0 hint_tooltip = "Amount of food purchased by the cook when mansion has less than 200 food" rounded angles to nearest integer for textures in save panel(v2c) replace line 7474 with: rect_rotation = 90.0 replace line 7465 with: rect_rotation = -90.0 adjusted positions of Close and Forfeit buttons on quest log to stand off from the border(v2c) replace line 6055 with: margin_bottom = 447.0 replace lines 6043-6045 with: margin_top = 360.0 margin_right = 823.0 margin_bottom = 400.0 adjusted positions of text on slave statistics panel(v2c) replace lines 5416-5421 with: margin_left = 420.0 margin_top = 20.0 margin_right = 731.0 margin_bottom = 390.0 replace lines 5405-5410 with: margin_left = 40.0 margin_top = 20.0 margin_right = 380.0 margin_bottom = 390.0 fixed background position for slave relatives popup(v4) remove lines 5363-5366: margin_left = -1.0 margin_top = -49.0 margin_right = -1.0 margin_bottom = -49.0 change "Brand" label a child of the brand button(v2c) add lines after 5185: [node name="Label2" type="Label" parent="MainScreen/slave_tab/stats/customization/brandbutton"] margin_left = 49.0 margin_top = -17.0 margin_right = 100.0 margin_bottom = 3.0 size_flags_horizontal = 2 size_flags_vertical = 0 custom_fonts/font = ExtResource( 45 ) text = "Brand" changed positions and sizes of buttons on slave customization panel(v2c) replace lines 5178-5180 with: margin_top = 30.0 margin_right = 175.0 margin_bottom = 70.0 replace lines 5167-5170 with: margin_left = 25.0 margin_top = -60.0 margin_right = 225.0 margin_bottom = -20.0 replace lines 5153-5156 with: margin_left = 25.0 margin_top = -110.0 margin_right = 225.0 margin_bottom = -70.0 replace lines 5141-5144 with: margin_left = 25.0 margin_top = -305.0 margin_right = 175.0 margin_bottom = -265.0 change "Brand" label a child of the brand button(v2c) remove lines 5128-5137. starts with: [node name="Label2" type="Label" parent="MainScreen/slave_tab/stats/customization"] changed positions and sizes of buttons on slave customization panel(v2c) replace lines 4883-4886 with: margin_left = 200.0 margin_top = 30.0 margin_right = 350.0 margin_bottom = 70.0 replace lines 4871-4874 with: margin_left = 249.0 margin_top = -110.0 margin_right = 419.0 margin_bottom = -70.0 replace lines 4859-4862 with: margin_left = 249.0 margin_top = -60.0 margin_right = 419.0 margin_bottom = -20.0 replace lines 4847-4850 with: margin_left = 200.0 margin_top = 90.0 margin_right = 350.0 margin_bottom = 130.0 replace lines 4832-4836 with: margin_left = 40.0 margin_top = -17.0 margin_right = 115.0 replace lines 4820-4823 with: margin_left = 25.0 margin_top = 90.0 margin_right = 175.0 margin_bottom = 130.0 adjusted positions of checkboxes and labels for rules(v2c) replace lines 4782-4784 with: margin_top = 191.0 margin_right = -136.0 margin_bottom = 219.0 replace lines 4762-4764 with: margin_top = 167.0 margin_right = -171.0 margin_bottom = 195.0 replace lines 4742-4744 with: margin_top = 143.0 margin_right = -142.0 margin_bottom = 171.0 replace lines 4722-4724 with: margin_top = 119.0 margin_right = -161.0 margin_bottom = 147.0 replace lines 4703-4705 with: margin_top = 318.0 margin_right = -146.0 margin_bottom = 346.0 replace lines 4684-4686 with: margin_top = 294.0 margin_right = -115.0 margin_bottom = 322.0 replace lines 4664-4666 with: margin_top = 270.0 margin_right = -152.0 margin_bottom = 298.0 replace lines 4646-4648 with: margin_top = 246.0 margin_right = -119.0 margin_bottom = 274.0 replace lines 4626-4628 with: margin_top = 64.0 margin_right = -95.0 margin_bottom = 92.0 replace lines 4605-4607 with: margin_top = 40.0 margin_right = -79.0 margin_bottom = 68.0 replace lines 4587-4590 with: margin_left = -250.0 margin_top = 99.0 margin_right = -141.0 margin_bottom = 119.0 replace lines 4571-4574 with: margin_left = -250.0 margin_top = 226.0 margin_right = -114.0 margin_bottom = 246.0 replace lines 4555-4557 with: margin_left = -250.0 margin_top = 20.0 margin_right = -121.0 adjusted the positions and sizes of the slave tab's work, sleep, and navigation buttons, now a slightly larger gap above the navigation buttons(v2c) changed work and sleep labels to be the children of their respective buttons(v2c) replace lines 3955-3958 with: margin_left = 25.0 margin_top = 290.0 margin_right = 175.0 margin_bottom = 330.0 replace lines 3945-3948 with: margin_left = 25.0 margin_top = 330.0 margin_right = 175.0 margin_bottom = 370.0 replace lines 3922-3942 with: [node name="sleep" type="OptionButton" parent="MainScreen/slave_tab/stats"] margin_left = 25.0 margin_top = 242.0 margin_right = 175.0 margin_bottom = 281.0 text = "Communal" align = 1 items = [ "Communal", null, false, -1, null, "Personal", null, false, -1, null, "Your Bed", null, false, -1, null, "Jail", null, false, -1, null ] selected = 0 [node name="sleeplabel" type="Label" parent="MainScreen/slave_tab/stats/sleep"] margin_left = -9.0 margin_top = -17.0 margin_right = 159.0 margin_bottom = 3.0 size_flags_horizontal = 2 size_flags_vertical = 0 custom_fonts/font = ExtResource( 45 ) custom_colors/font_color_shadow = Color( 0, 0, 0, 1 ) text = "Sleeping conditions" align = 1 replace lines 3909-3915 with: [node name="Label3" type="Label" parent="MainScreen/slave_tab/stats/workbutton" groups=[ "prisondisable", ]] margin_left = 24.0 margin_top = -17.0 margin_right = 125.0 margin_bottom = 3.0 replace lines 3899-3902 with: margin_left = 25.0 margin_top = 186.0 margin_right = 175.0 margin_bottom = 226.0 replace lines 3886-3889 with: margin_left = 25.0 margin_top = 570.0 margin_right = 175.0 margin_bottom = 610.0 replace lines 3873-3876 with: margin_left = 25.0 margin_top = 530.0 margin_right = 175.0 margin_bottom = 570.0 replace lines 3862-3865 with: margin_left = 25.0 margin_top = 410.0 margin_right = 175.0 margin_bottom = 450.0 replace lines 3852-3855 with: margin_left = 25.0 margin_top = 370.0 margin_right = 175.0 margin_bottom = 410.0 replace lines 3838-3845 with: margin_left = 25.0 margin_top = 490.0 margin_right = 175.0 margin_bottom = 530.0 replace lines 3824-3831 with: margin_left = 25.0 margin_top = 450.0 margin_right = 175.0 margin_bottom = 490.0 changed text on laboratory button from "Work on slaves" to "Modifications" since MC can be subject(v2c) replace line 2465 with: text = "Modifications" fixed visibility issues by moving text input for Default Title higher in list remove lines 2397-2415, starts with: [node name="defaultMasterNoun" type="LineEdit" parent="MainScreen/mansion/selfinspect"] adjust positions of gui on player inspect panel(v2c) replace lines 2391-2393 with: margin_top = 572.0 margin_right = 766.0 margin_bottom = 592.0 replace lines 2239-2242 with: margin_left = 20.0 margin_top = -59.0 margin_right = 159.0 margin_bottom = -20.0 replace lines 2228-2231 with: margin_left = -159.0 margin_top = -59.0 margin_right = -20.0 margin_bottom = -20.0 replace lines 2215-2218 with: margin_left = -159.0 margin_top = -179.0 margin_right = -20.0 margin_bottom = -140.0 added button for setting body image for player character(v3b) add these lines after 2209: [node name="selfbody" type="Button" parent="MainScreen/mansion/selfinspect"] anchor_left = 1.0 anchor_top = 1.0 anchor_right = 1.0 anchor_bottom = 1.0 margin_left = -159.0 margin_top = -99.0 margin_right = -20.0 margin_bottom = -60.0 size_flags_horizontal = 2 size_flags_vertical = 2 text = "Set Body Image" fixed typo "Set Portait"(v3b) replace line 2208 with: text = "Set Portrait" adjust positions of gui on player inspect panel(v2c) replace lines 2202-2205 with: margin_left = -159.0 margin_top = -139.0 margin_right = -20.0 margin_bottom = -100.0 replace lines 2189-2192 with: margin_left = -159.0 margin_top = -219.0 margin_right = -20.0 margin_bottom = -180.0 replace lines 2176-2179 with: margin_left = -159.0 margin_top = -259.0 margin_right = -20.0 margin_bottom = -220.0 replace lines 2163-2166 with: margin_left = -159.0 margin_top = -299.0 margin_right = -20.0 margin_bottom = -260.0 replace lines 2150-2153 with: margin_left = -159.0 margin_top = -339.0 margin_right = -20.0 margin_bottom = -300.0 fixed visibility issues by moving text input for Default Title higher in list add lines after 2144: [node name="defaultMasterNoun" type="LineEdit" parent="MainScreen/mansion/selfinspect"] anchor_left = 1.0 anchor_top = 1.0 anchor_right = 1.0 anchor_bottom = 1.0 margin_left = -231.0 margin_top = -407.0 margin_right = -20.0 margin_bottom = -373.0 text = "Master" placeholder_text = "Master" [node name="Label" type="Label" parent="MainScreen/mansion/selfinspect/defaultMasterNoun"] margin_left = 6.0 margin_top = -25.0 margin_right = 190.0 margin_bottom = -5.0 text = "Default Title" adjust positions of "Close" button on player inspect panel(v2c) replace lines 2137-2139 with: margin_top = -67.0 margin_right = -416.0 margin_bottom = -20.0 adjust positions of buttons on mansion info panel(v2c) replace lines 1391-1393 with: margin_top = -163.0 margin_right = -13.0 margin_bottom = -116.0 replace lines 1376-1378 with: margin_top = -113.0 margin_right = -13.0 margin_bottom = -66.0 replace lines 1350-1352 with: margin_top = 406.0 margin_right = 926.0 margin_bottom = 453.0 replace lines 1326-1328 with: margin_left = 569.0 margin_top = 556.0 margin_right = 746.0 fixed slave list scrollbar being pushed off screen when changing slave order(v3e) remove line 1139: scroll_horizontal_enabled = false adjust positions of navigation buttons(v2c) replace lines 1068-1070 with: margin_left = -658.0 margin_top = -83.0 margin_right = -540.0 replace lines 1004-1006 with: margin_left = -918.0 margin_top = -83.0 margin_right = -800.0 replace lines 910-912 with: margin_left = -518.0 margin_top = -83.0 margin_right = -402.0 replace lines 837-839 with: anchor_left = 1.0 anchor_top = 1.0 anchor_right = 1.0 anchor_bottom = 1.0 margin_left = -81.0 margin_top = -76.0 margin_right = -1.0 replace lines 814-816 with: margin_left = -367.0 margin_top = -83.0 margin_right = -286.0 adjust the positions and sizes of resource panel tooltip areas(v2c) replace lines 627-631 with: margin_left = 648.0 margin_top = 7.0 margin_right = 748.0 margin_bottom = 42.0 replace lines 617-620 with: margin_top = 7.0 margin_right = 535.0 margin_bottom = 42.0 replace lines 606-609 with: margin_top = 7.0 margin_right = 430.0 margin_bottom = 42.0 replace lines 592-595 with: margin_top = 7.0 margin_right = 324.0 margin_bottom = 42.0 replace lines 582-585 with: margin_top = 7.0 margin_right = 109.0 margin_bottom = 42.0 replace lines 571-573 with: margin_right = 643.0 margin_bottom = 42.0 replace lines 560-562 with: margin_right = 217.0 margin_bottom = 42.0 Mansion.gd changed the inventory to show everything by default(v3d) remove line 4136: globals.main.get_node('inventory').selectcategory(globals.main.get_node('inventory/everything')) changed text when removing traits from "Clarity Potion" to "Elixir of Clarity"(v3) replace line 4090 with: text += person.dictionary("Select physical trait to remove from $name. Requires 1 [color=yellow]Elixir of Clarity[/color], ") + str(manaCost) + " mana, " + str(goldCost) +" gold, and " + str(timeCost) + " days." added toggling text to the Hide UI button(v4) add lines after 4002: if $outside.visible: $hideui.text = "Hide UI" else: $hideui.text = "Show UI" changed farm job popup to become visible only after selecting a slave to add to the farm(v3c) add line after 3312: get_node("MainScreen/mansion/farmpanel/slavetofarm").show() remove line 3287: get_node("MainScreen/mansion/farmpanel/slavetofarm").show() added button for setting body image for player character(v3b) add function after line 2984: func _on_selfbody_pressed(): imageselect("body",globals.player) changed it so that abilities learned by player are defaultly active like slaves(v4) add line after 2974: globals.player.abilityactive.append(abil.code) removed old line of code that caused error messages in console(v3) remove line 2609: get_node("menucontrol/yesnopopup").hide() changed quest log to preserve button pressed state for selected repeatable quest rather than standard toggle(v4) replace 2594-2595 with: i.set_pressed(i.get_meta('quest') == quest) changed quest log to match changes to requirements for Melissa's request for a taurus girl(v3), moved second sentence to seperate line(v3e) replace line 2445 with: '10': "Bring Melissa a Taurus girl with huge lactating tits and at least three additional pairs of tits.\n\nSize and lactation can be altered with certain potions, while the laboratory lets you add and develop extra tits. ", fixed jail room upgrade text for "Better Furnishing" instead requiring "Soothing Incences"(v3e) replace line 2189 with: if globals.state.mansionupgrades.jailtreatment: updated text in jail to reduce confusion(v4) replace line 2188 with: text = 'You have '+str(prisoners.size()) + ' prisoner(s).\nYou have ' + str(globals.state.mansionupgrades.jailcapacity-prisoners.size()) + ' free cell(s).\nPrisoners can be disciplined at "Interactions" with meet setting. ' fixed high stress display on mansion's info panel replace line 2127 with: elif person.stress < 80: added "away" notes to slaves on the mansion's info panel, slaves hidden away for quests will not be listed for jobs(v2) add lines after 2094: elif jobdict.labassist.away.duration != 0: text += "[color=aqua]" + jobdict.labassist.name_short() + "[/color] [color=yellow](away)[/color]" add lines after 2087: elif jobdict.nurse.away.duration != 0: text += "[color=aqua]" + jobdict.nurse.name_short() + "[/color] [color=yellow](away)[/color]" add lines after 2082: elif jobdict.cooking.away.duration != 0: text += "[color=aqua]" + jobdict.cooking.name_short() + "[/color] [color=yellow](away)[/color]" add lines after 2074: elif jobdict.farmmanager.away.duration != 0: text += "[color=aqua]" + jobdict.farmmanager.name_short() + "[/color] [color=yellow](away)[/color]" add lines after 2067: elif jobdict.jailer.away.duration != 0: text += "[color=aqua]" + jobdict.jailer.name_short() + "[/color] [color=yellow](away)[/color]" add lines after 2061: elif jobdict.headgirl.away.duration != 0: text += "[color=aqua]" + jobdict.headgirl.name_short() + "[/color] [color=yellow](away)[/color]" replace line 2055 with: if jobdict.has(i.work) && i.away.at != 'hidden': fixed race URL in defeated person's description(v3e) add lines after 1515: if meta == 'race': get_tree().get_current_scene().showracedescript(get_node("MainScreen/slave_tab").person) _on_popupclosebutton_pressed() fixed headgirl, jailer, and farm jobs effecting slaves that are away(v2) replace line 1121 with: if person.sleep == 'farm' && person.away.duration == 0: replace line 1108 with: if person.sleep == 'jail' && person.away.duration == 0: replace line 1085 with: if i != headgirl && i.traits.find('Loner') < 0 && i.away.duration == 0 && i.sleep != 'jail' && i.sleep != 'farm': changed dark elf racial bonus to not prolong the debuffs from bandages and sedation(v4) replace line 1067 with: if person.race != 'Dark Elf' || (!i.code in ['bandaged','sedated'] && randf() > 0.5): added some basic recovery to slaves while away(v2) fixed sleeping places being overfilled by returning slaves(v2) replace lines 1062-1064 with: if person.away.at in ['rest','vacation']: slavehealing += 0.15 person.stress -= 20 if person.race == 'Orc': slavehealing += 0.15 if person.traits.has("Infirm"): slavehealing = slavehealing/3 person.health += slavehealing * person.stats.health_max if person.race == 'Fairy': person.stress -= rand_range(10,20) else: person.stress -= rand_range(5,10) person.energy += rand_range(20,30) + person.send*6 if person.away.duration == 0: text0.set_bbcode(text0.get_bbcode() + person.dictionary("$name returned to the mansion and went back to $his duty. \n")) var sleepChange = false if person.sleep != 'communal': match person.sleep: 'personal': sleepChange = globals.count_sleepers().personal > globals.state.mansionupgrades.mansionpersonal 'your': sleepChange = globals.count_sleepers().your_bed > globals.state.mansionupgrades.mansionbed 'jail': sleepChange = globals.count_sleepers().jail > globals.state.mansionupgrades.jailcapacity 'farm': if globals.count_sleepers().farm > variables.resident_farm_limit[globals.state.mansionupgrades.farmcapacity]: sleepChange = true person.job = 'rest' if sleepChange: person.sleep = 'communal' text0.set_bbcode(text0.get_bbcode() + person.dictionary("$name's sleeping place is no longer available so $he has moved to the communal area. \n")) person.away.at = '' changed lab operations to kill slaves the survived operation with less than 5 HP at end of day rather than wait till they get back(v2) replace line 1058 with: if person.away.at == 'lab' && person.health < 5: fixed slaves in master's bed interaction with away slaves(v2a) replace line 982 with: if i.sleep == 'your' && i != person && i.away.duration == 0: changed work pairing for tamer to remove uncivilized to be more appropriate replace line 826 with: if i.spec == 'tamer'&& i.away.duration == 0 && i.obed > 60 && (i.work == person.work || i.work in ['rest','nurse','headgirl'] || (i.work == 'jailer' && person.sleep == 'jail') || (i.work == 'farmmanager' && person.work in ['cow','hen'])): changed dark elf racial bonus to not prolong the debuffs from bandages and sedation(v4) replace line 754 with: if person.race != 'Dark Elf' || (!i.code in ['bandaged','sedated'] && randf() > 0.5): added text for slaves away with vacation tag(v2) add lines after 562: elif person.away.at == 'vacation': label.set_text(person.name_long() + ' will be on vacation for '+ str(person.away.duration)) fixed jail count on slave list for away slaves(v2a), fixed(v2b) replace line 501 with: elif person.sleep == 'jail' && (person.away.duration == 0 || person.away.at in ['rest','lab','in labor']): fixed error when hovering over race url when buying slave(v2c) add lines after 264: else: return slave_tab.gd added a 50% lightening of the color of the experience bar when a person is at 100%(v3e) replace lines 923-927 with: if person.xp >= 100: get_node("stats/statspanel/xp").tint_progress = Color(2.167,1.176,1.167,1) if person.levelupreqs.empty(): $stats/basics/levelupreqs.set_bbcode(person.dictionary("You don't know what might unlock $name's potential further, yet. ")) else: $stats/basics/levelupreqs.set_bbcode(person.levelupreqs.descript) else: get_node("stats/statspanel/xp").tint_progress = ColorN("white") changed the inventory to show everything by default(v3d) remove lines 576 and 568: globals.main.get_node('inventory').selectcategory(globals.main.get_node('inventory/everything')) fixed issues with meta links in self description panel(v2) replace line 457 with: if person == globals.player: globals.main._on_selfinspectlooks_pressed() else: slavetabopen() fixed slaves in jail working jobs(v4) add lines after line 432: if person.sleep == 'jail': person.work = 'rest' fixed stress change from branding slave(v3e) replace line 402 with: person.stress += 15 + person.conf/5 - person.loyal/10 fixed advanced slave brand not being disabled by lack of energy(v3) replace line 388 with: if globals.resources.mana >= 15 && globals.player.energy >= 20: removed semicolons from the end of each line in slave statistics(v2c) remove all ';' in lines 188-214 fixed presentation consistency for vaginal and anal penetration statistics(v2c) replace lines 204-205 with: text += "Vaginal penetrations: " + str(person.metrics.vag) + " time"+globals.fastif(person.metrics.vag == 1, '','s')+"\n" text += "Anal penetrations: " + str(person.metrics.anal) + " time"+globals.fastif(person.metrics.anal == 1, '','s')+"\n" changed hairstyles to selecting item in option button instead of setting text*(v2c) replace line 146 with: var hairstyleBtn = $stats/customization/hairstyle for i in range(hairstyleBtn.get_item_count()): if hairstyleBtn.get_item_text(i) == person.hairstyle: hairstyleBtn.select(i) break globals.gd added error code to text support, currently used by mod system(v3e) add lines after 1405: var errorText = [ "OK", "Generic", "Unavailable", "Unconfigured", "Unauthorized", "Parameter Range", "Out of memory", "File: not found", "File: Bad drive", "File: Bad path", "File: No permission", "File: Already in use", "File: Can't open", "File: Can't write", "File: Can't read", "File: Unrecognized", "File: Corrupt", "File: Missing dependencies", "File: End of file", "Can't open", "Can't create", "Query failed", "Already in use", "Locked", "Timeout", "Can't connect", "Can't resolve", "Connection", "Can't acquire resource", "Can't fork", "Invalid data", "Invalid parameter", "Already exists", "Does not exist", "Database: can't read", "Database: can't write", "Compilation failed", "Method not found", "Link failed", "Script failed", "Cyclic link", "Invalid declaration", "Duplicate symbol", "Parse", "Busy", "Skip", "Help", "Bug" ] func printErrorCode(msg, code=ERR_BUG, showOK = false): if code != OK: print("ERROR: ", msg, " Error code(", code, "): ", errorText[code]) elif showOK: print("OK: ", msg) quick fix for extra '/' in file paths add lines after 1302: if target.ends_with('/'): target.erase(target.length()-1,1) fix for farm crash add lines after 1278: if !state.mansionupgrades.has("farmmana"): state.mansionupgrades.farmmana = 0 removed creation of unnecessary person objects when loading save(v3f) remove line 1267: newslave = person.new() remove line 1259: newslave = person.new() remove line 1255: state.sebastianslave = person.new() fixed counts for sleepers(v2) replace line 674 with: if i.away.duration == 0 || i.away.at in ['rest','lab','in labor']: changed loadimage() function to work with non-imported images with 'res:' paths(v3b) replace line 279 with: if ResourceLoader.exists(path): fixed starting game with fullscreen option(v3g) add lines after 141: if rules.fullscreen == true: OS.set_window_fullscreen(true) fixed mixed up icons for executor and trapper(v2c) replace line 112 with: trapper = load("res://files/buttons/mainscreen/39.png"), replace line 108 with: executor = load("res://files/buttons/mainscreen/38.png"), imageselect.tscn changed portrait and body folder path selection to allow paths outside of user data replace line 255 with: access = 2 imageselect.gd fixed longer image names when selecting pictures manually, due to other changes made (v2) replace line 69 with: node.get_node("Label").set_text(i.replacen(currentpath,'').replacen('.jpg','').replacen('.png','')) fix problem with thumbnails caused by changes(v2a) replace line 62 with: var iconpath = i.replace(currentpath, thumbnailpath + type + '/') inventory.tscn changed some Popups'(hairchange, itemrename, and amnesia) TextureRects to Panels with bigpanel as custom style, fixes transparency adjusted layout of amnesia popup replace lines 1048-1050 with: texture_normal = ExtResource( 54 ) texture_pressed = ExtResource( 55 ) texture_hover = ExtResource( 56 ) replace line 1032 with: margin_bottom = 220.0 replace line 1030 with: margin_top = 15.0 replace line 1023 with: margin_bottom = 341.0 replace line 1021 with: margin_top = 302.0 replace line 1014 with: margin_bottom = 299.0 replace line 1012 with: margin_top = 265.0 replace line 1005 with: margin_bottom = 259.0 replace line 1003 with: margin_top = 225.0 remove lines 994 - 999: margin_left = 15.0 margin_top = -57.0 margin_right = 15.0 margin_bottom = -57.0 texture = ExtResource( 4 ) expand = true add line after 993: custom_styles/panel = ExtResource( 53 ) replace line 991 with: [node name="Panel" type="Panel" parent="amnesia"] remove line 953: expand = true replace line 952 with: custom_styles/panel = ExtResource( 53 ) replace line 949 with: [node name="Panel" type="Panel" parent="itemrename"] remove line 911 with: expand = true replace line 910 with: custom_styles/panel = ExtResource( 53 ) replace line 907 with: [node name="Panel" type="Panel" parent="hairchange"] remove "test" tooltip from costume slot in inventory(v3) remove line 606: hint_tooltip = "test" add "bigpanel" StyleBox resource for panel appearance, fixes transparency replace lines 55 - 57 with: [ext_resource path="res://files/bigpanel.tres" type="StyleBox" id=53] [ext_resource path="res://files/buttons/arrows/down.png" type="Texture" id=54] [ext_resource path="res://files/buttons/arrows/down-press.png" type="Texture" id=55] [ext_resource path="res://files/buttons/arrows/down-hl.png" type="Texture" id=56] replace line 1 with: [gd_scene load_steps=60 format=2] mainmenu.scn (changes need to be made in Godot Editor for .scn file) fixed active mod list transparency and adjust layout change type of node "TextureFrame/modpanel/activemodlist" from "PopupPanel" to "Popup" add child node of type "Panel" to previous node move to the top of list of siblings set size to (398, 578) for RichTextLabel and Label: set position to (30, 20) set size to (340, 530) fixed mainscreen not being aligned with the camera resulting in a grey bar at top of screen(v3c) change pos of node "mainscreen" to (0,0) changed notification panel that appears after applying mods to provide more functionality(v3e) for "TextureFrame/modpanel/restartpanel": add child node of type "Button" change name to "continuebutton" set position to (86, 208) set size to (126, 39) set text to "Confirm" set "pressed()" signal to connect to "../.." :: "_on_continuebutton_pressed()" for restartbutton: change position to (250, 208) change text to "Exit Game" for RichTextLabel: change position to (30, 30) change size to (402, 163) change Bb Code to "Mod list has been changed. Game must close for changes to take effect." set Selection Enabled to On added tooltips to mod screen buttons(v3e) for "TextureFrame/modpanel": for applymods: change hint to "Reset to backup and apply selected mods" for disablemods: change hint to "Reset to backup, removes all mods" for closemods: change hint to "Return to main menu" for modfolder: change hint to "Select new location for mod folder" for openmodfolder: change hint to "Ask OS to open mod folder" for activemods: change hint to "Show list of currently active mods" updated the help guide for modding and changed GUI to improve readability(v3c), added experimental guide for MacOSX modding(v3e) change node "TextureFrame/modpanel/Panel" set size to (1300, 708) set position to (-217, -12) change node "TextureFrame/modpanel/Panel/RichTextLabel" set size to (1260, 626) set postion to (20, 20) change node "TextureFrame/modpanel/Panel/helpclose" set position to (581, 651) added child node of type "ColorRect" to "TextureFrame/modpanel/Panel" move to the top of list of siblings set position to (10, 10) set size to (1280, 688) in Visibility, set Modulate to dc000000 in Visibility, enable "Show Behind Parent" change BbCode in node "TextureFrame/modpanel/Panel/RichTextLabel", lines of # are delimiters and not included ####################################################################################################################### This is a short guide for users and modders on the mod system. The game does not support modding on MacOSX at this time, though further down there is an experimental setup that may work. [color=yellow][center]For Users[/center] Only install the mods you know are safe. Strive team is not responsible for any damage caused by third party mods.[/color] The default mod folder varies by operating system, but can be located using the "Open Mod Folder" button found in the Mods menu. Beside it is a button containing the current mod folder location, which can be clicked to bring up a prompt to change the location. [color=yellow]How to install mods:[/color] 1. Download and put the mods in the mod folder. If a mod is compressed or archived(e.g., ZIP or RAR), then extract the contents. 2. Start the game and open the Mods menu. 3. Click on mods to select the ones to use and set their install order. 4. Click "Apply", wait until completion popup appears, and restart the game after it's closed. 5. If game fails to load, reinstall the game and try a different set or order of mods. [color=yellow]How to update mods:[/color] 1. Delete old version of the mods from the mod folder. 2. Download and put new version of the mods in the mod folder. If a mod is compressed or archived(e.g., ZIP or RAR), then extract the contents. 3. Start the game and open the Mods menu. 4. If any mods have changed folder name, click on those mods to select them and set their install order. 5. Click "Apply", wait until completion popup appears, and restart the game after it's closed. 6. If game fails to load, reinstall the game and try a different set or order of mods. [color=yellow]How to disable mods:[/color] 1. Start the game and open the Mods menu. 1. Unselect mods you no longer wish to use. 2. Click "Apply" and restart the game after its closed. OR Click "Reset" to disable all mods and restart the game after it's closed. [color=yellow]Common installation problems:[/color] 1. Check if the mod has any install instructions. Verify that you have the most recent, or appropriate, version of the mod and that it is compatible with your version of Strive. 2. The game is very specific about where it searches for the file paths of mods, and even a small deviation can cause the mod to have no effect. Each mod's folder is treated as the relative path equivalent to Strive's "file" folder(e.g., '.../mods/MOD_NAME/scripts' is equivalent to '.../STRIVE_FOLDER/files/scripts'). This fact can be used to compare files and folders in a mod for correctness. Also, renaming folders can break any mod that stores gameplay files in that folder. 3. When "Apply" or "Reset" are clicked, the game reverts script files to the files found in the "backup" folder. Only the currently selected mods will be active after "Apply", thus mods cannot be added by spreading them across multiple installs. 4. Having more than one mod change the same file can result in conflicts by overwriting the same code multiple times or changing the line numbers for other mods. Sometimes this can be resolved by flipping their install order. Sometimes they will require manually changing the code. The script files(.gd) are plain text files and can be edited with any decent text editor(e.g., Notepad++, or Sublime Text 3). [color=yellow][center]Experimental Setup for Modding on MacOSX[/center][/color] [color=yellow]This setup may not work for everyone, please have a backup of your game files before attempting.[/color] This guide is an adaptation of the post "How to make mods work on Mac OSX(without wine)" by RK76Manishog on the itch.io forum. You will need both the Mac version and a Windows version of the game. During this setup you may find that some folders are hidden, to show them press Command-Shift-Period. Open the Windows version. There is a hidden folder called ".import", it is important that it be visible. Delete the Strive.exe and icon.png.import files. Keep this folder open as it will be used again. Open the Mac version, right click on Strive For Power.app and click "Show Package Contents". Now, go into /Contents/Resources. You should see Strive For Power.pck and icon.icns. Delete the .pck file as you don't need it anymore. Move everything inside the Windows folder into /Contents/Resources. After that, run Strive For Power.app and see if it works, if it does, then you're done! If not, then make sure to re-read every step, and if it still doesn't work then seek help on itch.io or Discord. The default location to put mods on Mac is Users/YOUR_USER_NAME/Library/Application Support/Strive/mods. Sometimes you might find out that some mods don't work, not all hope is lost if you experience this. Go into your mods folder and right click the files inside of the specific mod. Then click "Get Info" and look in "Sharing & Permissions" which should be at the bottom. Make sure that you turn every file to "Read & Write", including the folder itself. [color=yellow]To install portrait packs:[/color] Open the folder /Users/YOUR_USER_NAME/Library/Application Support/Strive, you should see the folders called "bodies" and "portraits", if not then you will need to make those two folders. Once you download a portrait pack, simply place the files in their respective folders. [color=yellow][center]For Modders[/center][/color] The mod system does not provide any GUI for easier modding yet, its main objective is to provide simple mod management for users and support for multiple mods. Mods are stored in the mod folder, which has a default path of 'user://mods', where 'user://' is a relative path that depends on your system. The Mods menu provides the "Open Mod Folder" button that will ask your OS to display the mod folder, and button containing the current mod folder path, which can be clicked to bring up a prompt to change the path. The folder can have the file 'LoadOrder.ini', which tracks the install order and active mods. Each folder will be counted as a separate mod and displayed in the user's mod list. The each mod's folder should have a file named info.txt (if not found, one will be generated at '.../mods/MOD_NAME/info.txt'), which will hold a description of the mod to be shown in the Mods menu. On startup, if the backup folder does not already exist, the game automatically creates a backup copy of its script files(.gd) and stores them in 'res://backup', where 'res://' is a relative path that depends on where Strive executes from. A new backup can easily be created by deleting or renaming the backup folder and starting the game. Note, the mod system reverts script files to the files found in the "backup" folder, and it can erase any changes you have made to the game's script files. [color=yellow]Basic modding:[/color] Let's imagine you want to edit the script 'mainmenu.gd', which has a path of 'res://files/scripts/mainmenu.gd'. Create a folder in the game's mod folder with your mod's name. Add folder 'scripts' to it, and inside this add a copy of mainmenu.gd. The path of it will be 'user://mods/YOUR_MOD_FOLDER/scripts/mainmenu.gd'. Then you can edit anything you wish in your mod's copy and have those changes applied by the mod system. However, this is only optimal if you want to work with the entire script or just make your old changes into a mod. However, if each mod simply replaces the file, then they cannot coexist within the file. So the mod system provides tools for editing scripts with higher precision and efficiency. [color=yellow]How to edit existing script files (without entirely overwriting them):[/color] Find the code you want to change and identify the file-scoped definition that contains it. The definition will begin with a keyword('class', 'func', 'signal', 'var', 'onready var', 'const', 'enum') as the first text on a line(i.e., no tabs). Copy the entire definition into your mod file with the same name and path as the file you want to edit. Edit the contents of the copied definition to what you want it to be. The definition will be completely overwritten with the one provided by your file, and other parts of the file will be left untouched. Alternatively, if your mod provides a definition that does not match any already in the file, a new definition will be added to the end of the file. Example: Original file, 'res://example.gd': -------------------- var a = 10 func b(): print(10) -------------------- Your mod file, 'user://mods/YOUR_MOD_FOLDER/example.gd': -------------------- var a = 5 class c: var d = 4 func b(): print(1) print(2) -------------------- Resulting file, 'res://example.gd': -------------------- var a = 5 func b(): print(1) print(2) class c: var d = 4 -------------------- This is the cornerstone of the mod system: overwrite original file but only the parts you want to. However, in some cases you might want to edit just part of a definition(i.e. it is very long, or other modders might also access it). In such cases, you can add a special tag '' as the line above the definition. This will not overwrite whole definition with new code, but instead only add code at line X of a definition's contents. If X is 0, it will be added at the start; if x is -1, it will be added to the end. Example: Original file, 'res://example.gd': -------------------- func a(): print(10) class b: var c = 5 var d = 10 -------------------- Your mod file, 'user://mods/YOUR_MOD_FOLDER/example.gd': -------------------- func a(): print(1) print(2) class b: var e = 0 -------------------- Resulting file, 'res://example.gd': -------------------- func a(): print(1) print(2) print(10) class b: var c = 5 var e = 0 var d = 10 -------------------- The other tag available for easier modifications is ''. When added before the definition, it will ignore the contents of the provided definition and only remove the lines from X to Y in the original definition. X is the first line, and Y is the last line. It can be helpful to leave a note explaining what you intend to remove. Example: Original file, 'res://example.gd': -------------------- func a(): print(1) print(2) print(10) class b: var c = 5 var e = 0 var d = 10 -------------------- Your mod file, 'user://mods/YOUR_MOD_FOLDER/example.gd': -------------------- func a(): #literally anything class b: #removes variables c and e -------------------- Resulting file, 'res://example.gd': -------------------- func a(): print(1) print(10) class b: var d = 10 -------------------- Keep in mind that any changes to the code will shift line order for that definition, which may result in unexpected behavior in changes that follow, especially with other mods. [color=yellow]Custom files:[/color] You can use any files, images and other data, not included in the game, by giving it an unique name or path. However, for it to be called from other places you will need a path. For path you should use globals.modfolder as reference to user's mod folder. Example: var new_custom_script = load(globals.modfolder + "/YOUR_MOD_FOLDER/NEW_CUSTOM_SCRIPT.gd") As you can see, this system is still revolves around Godot script, but should make mod management a bit easier. [color=yellow][center]Detailed Mechanics[/center][/color] This section is intended for those who want to know more technical details for writing mods. If your mod does not behave the way you expected, then this may help clarify why. [color=yellow]How definitions are matched:[/color] Definitions are identified by using regular expressions, regexs for short, which use strings to define search patterns and report any text that matches the given patterns. These patterns are composed of sub-pattern groups that each report the text that they matched. Every group is automatically assigned a numeric index starting at 0 and some groups are given names, but for this guide they will be given names for the part of the syntax that they match. These groups are: entire match, leading comments, header, and body. The mod file and the original file both use the same regexs, which results in some odd modding syntax. Definitions are matched between the two files according to only the header groups, even a single difference will result in them not matching. [color=yellow]Types of changes:[/color] There are two categories of changes a mod file can make: tagged and untagged. Tags are lines such as '' and '' that are provided before definitions. Untagged changes allow definitions to be added or replaced. The groups used to apply changes depend on which tag, if any, is present. The AddTo tag adds the text found by the body group of a modded definition. The RemoveFrom tag only cares about the header of a modded definition. Untagged changes use the entire match group to add or replace a definition. [color=yellow]Line numbers for tags:[/color] Getting the right line numbers for tags is often a process of trial and error, so here are some tips to help. Make sure to use a text editor that will tell you the line numbers as this makes the process a lot simpler. For adding code at a line or removing a line, you get the index by subtracting the line number of the beginning of the definition from the line number you wish to edit and subtracting 1 from the difference. So i [color=yellow]Leading comments:[/color] Any line beginning with '#' is considered a comment, or non-code notes, by Godot scripts. The regex for every definition has a leading comments group, though only untagged changes will make use of them. The group will include any number of comment lines immediately before the header, so long as the '#' is at the start of the line and no line between the comment and the header is not included. Examples: -------------------- #not included [color=green]#included #included[/color] var a = 1 #not included #not included [color=green]#included[/color] var b = 2 -------------------- [color=yellow]Syntax of classes and functions:[/color] Example header groups: -------------------- class NAME func NAME static func NAME -------------------- Note, the rest of the line is not apart of the header or body groups; it can be anything as far as the mod system is concerned. Classes and functions use the same regex pattern for their body group. It is essentially defined as including all the lines that start with a tab until the last line that starts with a tab. There are exceptions to include empty lines or comment lines even if they don't start with a tab. Basically, it will try to match until the next file-scoped definition, then back-track to the last line starting with a tab. Examples: -------------------- func HEADER(): [color=green]var included = 1 #included included = 2 #included[/color] #not included, leading comment for variable var notIncluded = 3 -------------------- [color=yellow]Syntax of variables and their variants:[/color] Example header groups: -------------------- var NAME onready var NAME const NAME enum NAME -------------------- All these definitions use the same regex pattern for their body groups. There are two versions: multiple lines and single line. The multiple line version starts with a '=' followed by either '{' or '['. The following lines can contain anything, until a matching '}' or ']' are at the start of a line (note, the entire line will be included). When using the AddTo tag, you will need to use the full syntax for it to be matched by the regex. The '=' and the outer-most pair of '{}' or '[]' will be removed from the body group, and any non-empty lines in the body group will be added. Example: -------------------- var poem[color=green] = { 'roses' : 'red', 'violets' : 'blue' } #comment can be here due to regex shortcut[/color] -------------------- The single line version will include anything on a single line, except the start of the multiple line version. [color=yellow]Syntax of signals:[/color] This syntax is unique as it does not have a body group. Example header group: -------------------- signal NAME -------------------- [color=yellow]If you still have questions:[/color] The fastest way to get answers is the Strive4Power Discord, which is the second link on the main screen. Otherwise, try posting to a relevant thread or starting a new thread in Strive's itch.io community forum, which is the third link on the main screen. There is a link to the wiki as well, but that tends to be out of date. Or, if you are feeling brave, try opening 'res://scripts/mods/modpanel.gd' with a text editor and find out how the mod system works. ####################################################################################################################### mainmenu.gd fixed reputation when starting as Halfkin (v1a), properly fixed Halfkin and Demons(v3b), fixed for setget notifications(v3f) replace lines 1404-1406 with: elif player.race.find("Halfkin") >= 0: for i in globals.state.reputation: globals.state.reputation[i] += 15 replace lines 1397-1398 with: for i in globals.state.reputation: globals.state.reputation[i] -= 10 fixed rare chance for player or starting slave to start with less than 100% health(v3d) add line after 1388: player.health = 1000 add line after 1355: startSlave.health = 1000 fixed dropdown button for wings not matching person(v2) add lines after 985 if makeoverPerson.wings == i: get_node("TextureFrame/newgame/stage6/wings").select(get_node("TextureFrame/newgame/stage6/wings").get_item_count()-1) fixed quickstart having 1 portal randomly disabled(v4) replace line 621 with: #startingLocation = locationArray[rand_range(0, locationArray.size())] startingLocation = 'wimborn' fixed starting game with fullscreen option when game window is not selected(v3g) add lines after 176: if OS.is_window_fullscreen() && OS.get_window_position() != Vector2(0,0): OS.set_window_fullscreen(false) OS.set_window_fullscreen(true) add lines after 172: yield(get_tree().create_timer(0.1), "timeout") if OS.is_window_fullscreen() && OS.get_window_position() != Vector2(0,0): OS.set_window_fullscreen(false) OS.set_window_fullscreen(true) fixed starting game with fullscreen option(v3g) remove lines 154-155: if globals.rules.fullscreen == true: OS.set_window_fullscreen(true) dating.gd fixed double background transistion after sex during date, sex background is always mansion add line after 1091: get_parent().backgroundinstant('mansion') changed "away" tag for slaves that pass out drunk(v2) add line after 1041: person.away.at = 'rest' fixed chat and intimate talk to have diminishing chances of success(v3d) replace line 586 with: if randf() >= counter/10.0 && self.mood >= 7 && person.loyal >= 10: replace line 572 with: if counter < 3 || randf() >= counter/10.0+0.1: changed number of turns for meet interaction to be based on a global variable(v3b) fixed conflict of expected value types due to the global variable being a float(v3d) replace line 369 with: self.turns = int(variables.timeformeetinteraction) fixed formatting that does not conform to new mod system(v3) remove leading whitespace from line 298: } remove leading whitespace from line 30: } remove line 29(just don't like the blank line) events.gd changed "away" tag for Cali, Ayneris, and Zoe(v2) add line after 3056: zoe.away.at = 'study' add line after 3018: ayneris.away.at = 'rest' add line after 3007: ayneris.away.at = 'rest' replace line 2541 with: cali.away.at = '' fixed being able to progress quests without having the necessary slave(v4) add lines after 2539: if cali == null: return add lines after 1919: if cali == null: return fixed finale hostage text(v3) replace line 1851 with: text = finaleperson.dictionary(textnode.MainQuestFinaleGoodReleaseHade2) due to popular demand, zoe delivery quest now uses either inventory, instead of only the backpack as I had planned (currently the only quest outside mansion that still uses only storage)(v2) replace lines 1446-1448 with: if globals.state.getCountStackableItem('natureessenceing','any') >= 15 && globals.state.getCountStackableItem('fluidsubstanceing','any') >= 5 && globals.resources.food >= 500: globals.state.removeStackableItem('natureessenceing', 15, 'any') globals.state.removeStackableItem('fluidsubstanceing', 5, 'any') changed "away" tag for Emily and Tisha(v2) add line after 782: tisha.away.at = 'vacation' add line after 781: emily.away.at = 'vacation' simplified some code related to Tisha at the Gorn guild event(v4) replace lines 741-743 with: emily.tags.erase('nosex') replace lines 734-737 with: emily.consent = true emily.tags.erase("nosex") remove lines 717-719: for i in globals.slaves: if i.unique == "Emily": i.tags.erase('nosex') fixed Emily sprite and navigation GUI not displaying during search for Tisha at dorms with Emily, added slight reputation penalty for threatening (v3) replace line 593 with: globals.main.dialogue(state,self,text,buttons,sprite) add line after 581: globals.state.reputation.wimborn -= 2 add line after 568: globals.main.get_node("outside").mageorder() fixed being able to progress quests without having the necessary slave(v4) changed "away" tag for Emily and Tisha(v2) replace line 489 with: if emily == null: return emily.away.at = '' fixed being able to progress quests without having the necessary slave(v4) add lines after 275: if emily == null: return ############# forgot to check somebody's sex event, there was a dialogueclose() too soon? options.tres.gd changed gender balance text for clarity(v2c) replace line 85 with: get_node("TabContainer/Game/futasliderlabel").set_text('Random futa occurrence: ' + str(globals.rules['futa_chance']) + '% of females, ' + str(round((100-globals.rules['male_chance'])*globals.rules['futa_chance']/10)/10) + '% of people are futa') replace line 81 with: get_node("TabContainer/Game/malesliderlabel").set_text('Random gender occurrence balance: ' + str(globals.rules['male_chance']) + '% of people are males') futaslider(globals.rules['futa_chance']) fixed "Alise on Day End" game option by applying current setting to GUI add line after 54: get_node("TabContainer/Game/aliseoption").select(globals.rules.enddayalise) changed gender balance text for clarity(v2c) add line after 47: get_node("TabContainer/Game/futaslider").set_editable(globals.rules.futa) replace line 44 with: if (globals.rules['futa']): get_node("TabContainer/Game/futasliderlabel").set_text('Random futa occurrence: ' + str(globals.rules['futa_chance']) + '% of females, ' + str(round((100-globals.rules['male_chance'])*globals.rules['futa_chance']/10)/10) + '% of people are futa') else: get_node("TabContainer/Game/futasliderlabel").set_text('Random futa occurrence: 0% of females, 0% of people are futa') replace line 39 with: get_node("TabContainer/Game/malesliderlabel").set_text('Random gender occurrence balance: ' + str(globals.rules['male_chance']) + '% of people are males') changed disabling children to not hide noadults option, also no longer adds unused "adults" rule(v2c) replace line 31 with: globals.rules.noadults = false add '#' to the beginning of lines 27-33 changed futa slider to be disabled rather than hidden, gender balance text for clarity(v2c) replace line 25 with: futaslider(globals.rules['futa_chance']) get_node("TabContainer/Game/futaslider").set_editable(true) replace line 20 with: get_node("TabContainer/Game/futasliderlabel").set_text('Random futa occurrence: 0% of females, 0% of people are futa') get_node("TabContainer/Game/futaslider").set_editable(false) traits.gd added "sexual" tag to "Sex-crazed" and "Slutty", which changes how the traits are displayed(v3) after line 555 add: "sexual", after line 108 add: "sexual", fixed "Pretty Voice" conflicting with "Mute" add comma to line 32: "Foul Mouth", add line after 32: "Pretty voice" assets.gd add some missing fur colors to random selection replace line 119 with: return getrandomfromarray(['white', 'gray', 'orange_white','black_white','black_gray','black','orange','brown']) combat.gd changed player to be effected by Exhausted debuff as well(v3d) remove lines 1191-1192: if combatant.person == globals.player: return fixed error with reporting defeated members of the combat group(v3), fixed wrong text(v3e) remove lines 624-629: var text = '' for i in playergroup: if i.state == 'defated': text += '\n[color=#ff4949]' + i.name + ' has fallen. [/color]' playergroup.remove(playergroup.find(i)) add line after 593: scene.combatlog += "\n[color=#ff4949]" + _slave.name + " has died. [/color]" add line after 587: scene.combatlog += "\n[color=#ff4949]" + _slave.name + " has been defeated. [/color]" fixed error that prevented slaves from receiving 15 hp after being knocked out in combat(v2) replace line 576 with: scene.playergroup.remove(scene.playergroup.find(self)) fixed abilites not appearing disabled when not enough mana or energy(v3e) replace line 509 with: var cost = skill.costmana if globals.state.spec == 'Mage': cost = round(cost/2) newbutton.set_disabled(cooldowns.has(skill.code) || skill.costenergy > energy || cost > globals.resources.mana) fixed some minor indexing errors when player is defeated in combat(v4) replace line 491 with: if scene.playergroup.size() > 0 && scene.playergroup[0].effects.has('mindreadeffect'): fixed event enemies being given increased stats for exploring deeper region(v4) replace line 379 with: if scene.get_parent().get_node("explorationnode").deeperregion && !scene.nocaptures: fixed selecting player's combatants with F-keys, added selecting targets with F-keys when ability is selected, cancel is ESC(v4) replace lines 305-306 with: if event.as_text().length() in [2,3] && event.as_text()[0] == 'F' && $win.visible == false: var value = int(event.as_text().right(1)) if period == 'base': if playergroup.size() >= value: playergroup[value-1].node.emit_signal('pressed') elif period == 'skilltarget': if enemygroup.size() >= value: enemygroup[value-1].node.emit_signal('pressed') replace line 297 with: if period == 'skilltarget' && (event.is_action_pressed("RMB") || event.is_action_pressed("escape")): fixed some minor indexing errors when player is defeated in combat(v4) replace line 237 with: if combatant.group == 'enemy' && playergroup.size() > 0 && playergroup[0].effects.has('mindreadeffect'): laboratory.gd fixed typo that prevented description for augmented scales from showing(v2) replace line 565 with: elif modification.code == 'mod' && action == 'scales': dailyevents.gd changed "away" tag for vacation, stranger disrespect, and injured slave events(v2) add line after 540: person.away.at = 'rest' add line after 537: person.away.at = 'rest' add line after 422: person.away.at = 'stranger' add line after 384: person.away.at = 'vacation' fixed slaves not appearing when resolving event with sex(v2) replace line 198 with: get_parent().sexmode = 'sex' replace line 203 with: get_parent().sexmode = 'sex' minor fixes and changes to the text of escaped slave event(v3) replace line 26 with: escapedslave = ["During the morning you receive a report that $name has caught a trespasser on the mansion grounds. Apparently, it's a runaway slave who recently escaped from the town. You speak to the $2child, $2he tells you that he has been treated very badly by $2his masters, which you confirm by numerous visible bruises. $2He says $2he couldn't find much food in past few days. ", "You offer $2name the chance to join your household and be provided with food and shelter. You also promise to treat $2him better than $2his previous owners. With little options and an empty stomach, $2he takes your offer, at least for now. $2name now belongs to you.", "You order the escaped slave to be tied up tightly and return $2him to town. After finding $2his previous owners you manage to earn some gold for your service.", "You decide that the $2child's life is of no interest to you. You threaten to punish $2him greatly if you see $2him again. "], #options: keep person to yourself, return person to city, act disinterested outside.gd simplified the code tracking of location for slave guilds/markets, which also fixes an obscure bug related to Slavers and Umbra(v4) replace line 2389 with: $bigmappanel/ScrollContainer/Control.centermap(main.exploration.currentzone.code) fixed infotext when releasing captured slave(v2) replace line 2343 with: get_parent().infotext('You have released '+ partyselectedslave.name, 'yellow') fixed preserved deeperregion status due to teleport(v4) add line after 2265: main.exploration.deeperregion = false changed "away" tag when slaves return on their own after player uses teleport seal(v2) replace line 2264 with: var temp = globals.state.findslave(i) temp.away.duration = round(rand_range(1,3)) temp.away.at = 'travel back' fixed checks for low mana and not mind reading player in outside's control menu(v4) replace lines 2241-2250 with: if spell.code == 'mindread' && partyselectedslave == globals.player: get_node("playergroupdetails/Panel/usebutton").set_disabled(true) elif globals.resources.mana >= cost: if spell.code == 'guidance': get_node("playergroupdetails/Panel/usebutton").set_disabled(get_parent().exploration.inencounter) elif spell.code == 'mark': get_node("playergroupdetails/Panel/usebutton").set_disabled(!get_parent().exploration.currentzone.combat) else: get_node("playergroupdetails/Panel/usebutton").set_disabled(partyselectedslave == null) else: get_node("playergroupdetails/Panel/usebutton").set_disabled(true) changed the deselection behavior of outside's control menu to be less aggressive(v4) player is now listed in outside's control menu in same order as displayed on outside's player group panel(v4) add line after 2206: get_node("playergroupdetails").popup() add line after 2194: selectpartymember(partyselectedslave) replace line 2159: for i in [globals.player.id] + globals.state.playergroup: replace lines 2137-2140 with: if !backpackselecteditem: get_node("playergroupdetails/Panel/itemdescript").set_bbcode("") get_node("playergroupdetails/Panel/discardbutton").set_disabled(true) get_node("playergroupdetails/Panel/usebutton").set_disabled(true) replace lines 2130-2132 with: if globals.state.getCountStackableItem(backpackselecteditem,'backpack') <= 0: backpackselecteditem = null if partyselectedslave != null: var foundSelected = false for i in [globals.player.id] + globals.state.playergroup: if str(i) == str(partyselectedslave.id): foundSelected = true for i in globals.state.capturedgroup: if i == partyselectedslave: foundSelected = true if !foundSelected: partyselectedslave = null if !globals.spelldict.get(backpackselectedspell,{}).get('learned'): backpackselectedspell = null fixed being able to progress quests without having the necessary slave(v4) replace line 2023 with: for i in globals.slaves: if i.unique == 'Cali': array.insert(1,{name = "Visit local bar", function = "calibarquest"}) break simplified the code tracking of location for slave guilds/markets, which also fixes an obscure bug related to Slavers and Umbra(v4) remove line 1920: sellslavelocation = 'sebastian' changed Umbra Exchange to allow multiple simultaneous exchanges(v2) replace function exchangeitemsconfirm, at line 1768 with: func exchangeitemsconfirm(): var numNew = ItemsForExchange.size() / 3 for i in ItemsForExchange: globals.state.unstackables.erase(i.id) ItemsForExchange.clear() for i in range(numNew): var newitem = globals.items.createunstackable(globals.weightedrandom(treasurepool)) if newitem.enchant != 'unique': if randf() >= 0.3: globals.items.enchantrand(newitem, 2) else: globals.items.enchantrand(newitem) #newitem.enchant = 'rare' globals.state.unstackables[newitem.id] = newitem if numNew < 6: get_parent().infotext('Recieved '+ newitem.name + ' from exchange','green') if numNew >= 6: get_parent().infotext('Recieved many items from exchange','green') exchangeRefresh() replace line 1758 with: $shoppanel/exchange/TradeButton.disabled = itemarray.size() % 3 != 0 changed Umbra Exchange button to toggle visibility(v2) also changed to avoid toggling visibility after each exchange(v2a) changed function used for loading item icons to support non-imported images(v3b) replace function exchangeitems, at line 1730 with: func exchangeitems(): if $shoppanel/exchange.visible: $shoppanel/exchange.visible = false return else: $shoppanel/exchange.visible = true exchangeRefresh() calculateexchange() add function before the function exchangeitems: func exchangeRefresh(): for i in $shoppanel/exchange/ScrollContainer/GridContainer.get_children(): if i.name != 'Button': i.hide() i.free() for i in globals.state.unstackables.values(): if i.owner == null && i.enchant == 'basic': var newbutton = $shoppanel/exchange/ScrollContainer/GridContainer/Button.duplicate() newbutton.show() newbutton.get_node('Icon').texture = globals.loadimage(i.icon) $shoppanel/exchange/ScrollContainer/GridContainer.add_child(newbutton) newbutton.connect('mouse_entered', globals, 'itemtooltip', [i]) newbutton.connect("mouse_exited", globals, 'itemtooltiphide') newbutton.connect("pressed", self, 'calculateexchange') newbutton.set_meta("item", i) fixed Umbra Exchange remaining visible after accessing store(v2) add line after 1716: $shoppanel/exchange.visible = false added update of itembar on right side of screen after exiting shop(v4) add line after 1691: playergrouppanel() changed it so that abilities learned by player are defaultly active like slaves(v4) add line after 1589: globals.player.abilityactive.append(spell.code) fixed rank-up from giving giant breasted taurus girl to Melissa(v2c) replace line 1525 with: globals.state.rank = 4 changed it so that abilities learned by player are defaultly active like slaves(v4) add line after 1499: globals.player.abilityactive.append('mindread') changed requirements for Melissa's request for a taurus girl to better match quest text and prior requirement for laboratory(v3) replace line 1475 with: reqs = "person.race == 'Taurus' && person.titssize == 'huge' && person.lactation == true && person.titsextradeveloped && person.titsextra >= 3" added hint text when attempting to give Melissa her potion but it is not in the backpack(v3d) replaceline 1404 with: if globals.state.getCountStackableItem('youthingpot','inventory') > 0: text = ("You forgot to bring the Youthing Elixir in your backpack and decide it is unwise to see Melissa without her delivery right now.") else: text = ("You decide it is unwise to see Melissa without her delivery right now.") fixed "Find Melissa" option being available in sandbox mode(v4) replace line 1299 with: elif globals.state.mainquest >= 3 && globals.state.mainquest < 40 && globals.state.mainquestcomplete != true: simplified the code tracking of location for slave guilds/markets, which also fixes an obscure bug related to Slavers and Umbra(v4) replace line 1199 with: slaveguild(guildlocation) changed "away" tag when slaves are sent to guild for services(v2) add line after 1191: person.away.at = 'training' add line after 1183: person.away.at = 'training' add line after 1172: person.away.at = 'training' simplified the code tracking of location for slave guilds/markets, which also fixes an obscure bug related to Slavers and Umbra(v4) replace line 883 with: globals.state.reputation[guildlocation] += 10 replace line 880 with: globals.state.reputation[guildlocation] += 5 replace line 877 with: globals.state.reputation[guildlocation] += 3 replace line 871 with: main.popup(offeredslave.dictionary('You hand away $name and receive your reward. \n[color=yellow]You have gained ' + str(selectedquest.reward/10) + ' XP.[/color]\n\n[color=green]Your reputation with ' + guildlocation.capitalize() + " has increased.[/color]")) removed old line of code that caused error messages in console(v3) remove line 861: main.get_node("menucontrol/yesnopopup").visible = false simplified the code tracking of location for slave guilds/markets, which also fixes an obscure bug related to Slavers and Umbra(v4) replace line 847 with: slaveguild(guildlocation) replace lines 800-805 with: questarray = globals.state.repeatables.get(guildlocation + 'slaveguild', []) replace lines 759-771 with: elif guildlocation == 'sebastian': sebastian() func clearselection(temp = ''): selectedslave = null selectedslaveprice = 0 mansion.maintext = '' if temp == 'buy': if guildlocation == 'slavers': mansion.maintext = '[color=yellow]Purchased slave is added to your group. [/color]' else: mansion.maintext = '[color=yellow]Your newly purchased slave has been sent to your mansion. [/color]' show combat group panel when done viewing slaves at Umbra(v2) simplified the code tracking of location for slave guilds/markets, which also fixes an obscure bug related to Slavers and Umbra(v4) replace line 757 with: if guildlocation == 'umbra': get_parent().get_node("explorationnode").zoneenter('umbra') get_node("playergrouppanel/VBoxContainer").visible = true elif globals.guildslaves.has(guildlocation): simplified the code tracking of location for slave guilds/markets, which also fixes an obscure bug related to Slavers and Umbra(v4) simplified a bit of logic for text around lines 719-720 and 748-749(v4a) replace lines 742-751 with: if location == 'sebastian': newbutton.get_node('price').set_text(str(round(person.sellprice(true)*0.7))+ ' gold') elif location == 'umbra': newbutton.get_node('price').set_text(str(person.sellprice(true))+ ' gold') else: newbutton.get_node('price').set_text(str(person.sellprice()) + ' gold') newbutton.set_meta('person', person) newbutton.connect('pressed',self,'selectslavesell',[person, location]) replace lines 714-720 with: func sellslavelist(location): guildlocation = location var text = 'Select a person you wish to sell. ' if location in ['wimborn','gorn','frostford']: text += "You will receive Mansion Upgrade points if person haven't been registered before and is not rebellious." elif location in ['sebastian','umbra']: text = "[color=aqua]Selling slaves here will still provide upgrade points even if they are rebellious, but will lower your reputation. [/color]" replace line 709 with: sellslavelist(guildlocation) replace line 706 with: if guildlocation != 'sebastian': replace lines 701-702 with: if globals.guildslaves.has(guildlocation): globals.guildslaves[guildlocation].append(selectedslave) changed reputation penalty for selling Orc, Goblin, or Centaur slaves from Frostford to Gorn(v3e) replace line 698 with: reputationloss[1][1] += 10 simplified the code tracking of location for slave guilds/markets, which also fixes an obscure bug related to Slavers and Umbra(v4) replace line 688 with: elif guildlocation in ['sebastian','umbra'] && selectedslave.fromguild == false: replace line 676 with: slaveguildslaves(guildlocation) replace line 667 with: if guildlocation == 'slavers': show combat group panel when done viewing slaves at Umbra(v2) show combat group panel when done viewing slavers' slaves(v3e) simplified the code tracking of location for slave guilds/markets, which also fixes an obscure bug related to Slavers and Umbra(v4) replace lines 657-662: if guildlocation == 'slavers': get_parent().get_node("explorationnode").slaversenc(2) get_node("playergrouppanel/VBoxContainer").visible = true elif guildlocation == 'umbra': get_parent().get_node("explorationnode").zoneenter('umbra') get_node("playergrouppanel/VBoxContainer").visible = true else: slaveguild(guildlocation) simplified the code tracking of location for slave guilds/markets, which also fixes an obscure bug related to Slavers and Umbra(v4) made correction to which towns always give upgrade points on line 638(v4a) remove lines 652-653: var closefunction replace line 638 with: elif !location in ['wimborn','gorn','frostford'] || (selectedslave.obed >= 90 && selectedslave.fromguild == false && selectedslave.effects.has('captured') == false): replace lines 626-632 with: func selectslavesell(person, location): if location == 'sebastian': selectedslaveprice = round(person.sellprice(true)*0.7) elif location == 'umbra': selectedslaveprice = person.sellprice(true) else: selectedslaveprice = person.sellprice() changed how mindread button updates when selling slaves to fix issues with slavers and mana cost when player is Mage(v4) replace lines 620-623 with: var cost = 5 if globals.state.spec == 'Mage': cost = cost/2 globals.resources.mana -= cost mindread = true get_node("slavebuypanel/mindreadbutton").disabled = true if selectedslave != null: selectslavebuy(selectedslave) remove lines 603-606: if globals.spelldict.mindread.learned == true && globals.resources.mana >= 5 && mindread == false: get_node("slavebuypanel/mindreadbutton").set_disabled(false) else: get_node("slavebuypanel/mindreadbutton").set_disabled(true) simplified the code tracking of location for slave guilds/markets, which also fixes an obscure bug related to Slavers and Umbra(v4) replace line 573 with: if location != 'slavers': replace line 564 with: if location == 'slavers': changed how mindread button updates when selling slaves to fix issues with slavers and mana cost when player is Mage(v4) add lines after 545: var cost = 5 if globals.state.spec == 'Mage': cost = cost/2 get_node("slavebuypanel/mindreadbutton").text = "Use Mind Read (" +str(cost)+ ")" get_node("slavebuypanel/mindreadbutton").hint_tooltip = "Allows to see more information about the slaves.\nCosts " +str(cost)+ " mana" get_node("slavebuypanel/mindreadbutton").disabled = mindread == true || globals.spelldict.mindread.learned == false || globals.resources.mana < cost simplified the code tracking of location for slave guilds/markets, which also fixes an obscure bug related to Slavers and Umbra(v4) replace line 544 with: func slaveguildslaves(location): guildlocation = location remove line 540: var sellslavelocation replace line 454 with: var array = [{name = 'See slaves for sale',function = 'slaveguildslaves', args = 'frostford'},{name = 'Offer your servants',function = 'sellslavelist', args = 'frostford'}, {name = 'See custom requests', function = 'slaveguildquests'}, {name = 'Services for Slaves',function = 'slaveservice'}, {name = 'Leave', function = 'tofrostford'}] replace line 417 with: var array = [{name = 'See slaves for sale',function = 'slaveguildslaves', args = 'gorn'}, {name = 'Offer your servants',function = 'sellslavelist', args = 'gorn'}, {name = 'See custom requests', function = 'slaveguildquests'},{name = 'Services for Slaves',function = 'slaveservice'}] replace line 398 with: var array = [{name = 'See slaves for sale', function = 'slaveguildslaves', args = 'wimborn'}, {name = 'Offer your servants',function = 'sellslavelist', args = 'wimborn'}, {name = 'See custom requests', function = 'slaveguildquests'},{name = 'Services for Slaves',function = 'slaveservice'},{name = 'Leave', function = 'town'}] remove line 380: sellslavelocation = 'guild' changed tooltip for outside combat group stress bars by removing the decimal values and adding "/100" for reference replace line 283 with: parentnode.get_node('stress').hint_tooltip = "Stress: " + str(floor(person.stress)) + "/100" fixed slave's lust bar being visible outside despite never being updated(v4) replace line 281 with: parentnode.get_node("lust").visible = false changed color of experience bar outside to match color in mansion and added 50% lightened color when person has 100%(v3e) add lines after 278: if person.xp == 100: parentnode.get_node("xp").tint_progress = Color(0.65,0.87,0.875,1) else: parentnode.get_node("xp").tint_progress = Color(0.3,0.74,0.75,1) fixed lack of visual change when toggling active abilities of non-selected combatant during combat causes selected combatant to change(v4) replace line 236 with: combatant.selectcombatant() changed function used for loading item icons to support non-imported images(v3b) replace line 194 with: $playergrouppanel/characterinfo.get_node(i).texture_normal = globals.loadimage(item.icon) fixed GUI sizing problem related to scroll bar being visible when init(v4) add lines after 41: get_node("playergroupdetails/Panel/TabContainer/Items").get_node("_v_scroll").visible = false get_node("playergroupdetails/Panel/TabContainer/Spells").get_node("_v_scroll").visible = false simplified the code tracking of location for slave guilds/markets, which also fixes an obscure bug related to Slavers and Umbra(v4) remove line 11: var currentzone remove line 9: var location = '' outside.tscn added updated text when amount is updated(enter or tab will cause update when typing new value)(v2a) add line after 3118: [connection signal="value_changed" from="shoppanel/inventory/amountselect/SpinBox" to="shoppanel/inventory" method="_on_SpinBox_value_changed"] fixed health and energy bars displaying incorrectly when selecting party member to open treasure chest(v2) remove line 3009: exp_edit = true remove line 2998: exp_edit = true adjusted positions and sizes of GUI in outside's control menu(v4) replace lines 2662-2663 with: custom_styles/fg = SubResource( 24 ) custom_styles/bg = SubResource( 25 ) replace line 2638 with: custom_styles/panel = SubResource( 30 ) replace line 2593 with: custom_fonts/font = SubResource( 29 ) replace line 2492 with: custom_fonts/font = SubResource( 29 ) replace line 2144 with: custom_fonts/font = SubResource( 28 ) replace line 1369 with: custom_fonts/font = SubResource( 27 ) replace line 1346 with: custom_styles/panel = SubResource( 26 ) replace lines 1219-1332 with: margin_top = -66.0 margin_right = -130.0 margin_bottom = -38.0 size_flags_horizontal = 2 size_flags_vertical = 2 custom_styles/fg = SubResource( 24 ) custom_styles/bg = SubResource( 25 ) step = 1.0 value = 40.0 percent_visible = false [node name="Label" type="Label" parent="playergroupdetails/TextureProgress"] margin_left = 120.0 margin_top = 29.0 margin_right = 277.0 margin_bottom = 49.0 size_flags_horizontal = 2 size_flags_vertical = 0 align = 1 [node name="return" type="Button" parent="playergroupdetails"] anchor_top = 1.0 anchor_bottom = 1.0 margin_left = 28.0 margin_top = -69.0 margin_right = 191.0 margin_bottom = -27.0 size_flags_horizontal = 2 size_flags_vertical = 2 text = "Return to Mansion" [node name="quicksell" type="Button" parent="playergroupdetails"] anchor_top = 1.0 anchor_bottom = 1.0 margin_left = 211.0 margin_top = -69.0 margin_right = 370.0 margin_bottom = -27.0 size_flags_horizontal = 2 size_flags_vertical = 2 text = "Quicksell Captives" [node name="TabContainer" type="TabContainer" parent="playergroupdetails"] margin_left = 30.0 margin_top = 16.0 margin_right = 600.0 margin_bottom = 366.0 size_flags_horizontal = 2 size_flags_vertical = 2 [node name="Party" type="ScrollContainer" parent="playergroupdetails/TabContainer"] anchor_right = 1.0 anchor_bottom = 1.0 margin_left = 10.0 margin_top = 40.0 margin_right = -10.0 margin_bottom = -10.0 size_flags_horizontal = 2 size_flags_vertical = 2 [node name="HBoxContainer" type="VBoxContainer" parent="playergroupdetails/TabContainer/Party"] size_flags_horizontal = 2 size_flags_vertical = 2 [node name="Button" type="Button" parent="playergroupdetails/TabContainer/Party/HBoxContainer"] visible = false margin_right = 400.0 margin_bottom = 50.0 rect_min_size = Vector2( 400, 50 ) size_flags_horizontal = 2 size_flags_vertical = 2 toggle_mode = true clip_text = true [node name="Captured Slaves" type="ScrollContainer" parent="playergroupdetails/TabContainer"] visible = false anchor_right = 1.0 anchor_bottom = 1.0 margin_left = 10.0 margin_top = 40.0 margin_right = -10.0 margin_bottom = -10.0 size_flags_horizontal = 2 size_flags_vertical = 2 [node name="HBoxContainer" type="VBoxContainer" parent="playergroupdetails/TabContainer/Captured Slaves"] size_flags_horizontal = 2 size_flags_vertical = 2 [node name="Button" type="Button" parent="playergroupdetails/TabContainer/Captured Slaves/HBoxContainer"] visible = false margin_right = 400.0 margin_bottom = 50.0 rect_min_size = Vector2( 400, 50 ) size_flags_horizontal = 2 size_flags_vertical = 2 toggle_mode = true clip_text = true [node name="setfree" type="TextureButton" parent="playergroupdetails/TabContainer/Captured Slaves/HBoxContainer/Button"] margin_left = 460.0 margin_top = 3.0 margin_right = 505.0 margin_bottom = 48.0 size_flags_horizontal = 2 size_flags_vertical = 2 texture_normal = ExtResource( 46 ) expand = true [node name="inspect" type="TextureButton" parent="playergroupdetails/TabContainer/Captured Slaves/HBoxContainer/Button"] margin_left = 410.0 margin_top = 3.0 margin_right = 455.0 replace lines 944-1143 with: margin_left = 20.0 margin_top = 20.0 margin_right = -20.0 margin_bottom = -20.0 size_flags_horizontal = 2 size_flags_vertical = 2 [node name="BackPanel" type="Panel" parent="playergroupdetails"] margin_right = 1322.0 margin_bottom = 730.0 custom_styles/panel = SubResource( 17 ) [node name="Panel" type="Panel" parent="playergroupdetails"] anchor_left = 1.0 anchor_right = 1.0 anchor_bottom = 1.0 margin_left = -630.0 margin_top = 40.0 margin_right = -30.0 margin_bottom = -80.0 size_flags_horizontal = 2 size_flags_vertical = 2 custom_styles/panel = SubResource( 18 ) [node name="itemdescript" type="RichTextLabel" parent="playergroupdetails/Panel"] anchor_left = 1.0 anchor_right = 1.0 anchor_bottom = 1.0 margin_left = -315.0 margin_top = 40.0 margin_right = -40.0 margin_bottom = -150.0 size_flags_horizontal = 2 size_flags_vertical = 2 bbcode_enabled = true [node name="usebutton" type="Button" parent="playergroupdetails/Panel"] anchor_left = 1.0 anchor_top = 1.0 anchor_right = 1.0 anchor_bottom = 1.0 margin_left = -268.0 margin_top = -120.0 margin_right = -90.0 margin_bottom = -81.0 size_flags_horizontal = 2 size_flags_vertical = 2 text = "Use" [node name="discardbutton" type="Button" parent="playergroupdetails/Panel"] anchor_left = 1.0 anchor_top = 1.0 anchor_right = 1.0 anchor_bottom = 1.0 margin_left = -268.0 margin_top = -70.0 margin_right = -90.0 margin_bottom = -31.0 size_flags_horizontal = 2 size_flags_vertical = 2 text = "Discard" [node name="TabContainer" type="TabContainer" parent="playergroupdetails/Panel"] editor/display_folded = true anchor_bottom = 1.0 margin_left = 5.0 margin_top = -24.0 margin_right = 240.0 margin_bottom = -7.0 size_flags_horizontal = 2 size_flags_vertical = 2 [node name="Items" type="ScrollContainer" parent="playergroupdetails/Panel/TabContainer"] anchor_right = 1.0 anchor_bottom = 1.0 margin_left = 10.0 margin_top = 40.0 margin_right = -10.0 margin_bottom = -11.0 rect_min_size = Vector2( 215, 0 ) size_flags_horizontal = 3 size_flags_vertical = 3 scroll_horizontal_enabled = false scroll_vertical_enabled = false [node name="VBoxContainer" type="VBoxContainer" parent="playergroupdetails/Panel/TabContainer/Items"] margin_right = 215.0 margin_bottom = 40.0 rect_min_size = Vector2( 215, 0 ) size_flags_horizontal = 2 size_flags_vertical = 2 custom_constants/separation = 0 [node name="Button" type="Button" parent="playergroupdetails/Panel/TabContainer/Items/VBoxContainer"] visible = false margin_right = 215.0 margin_bottom = 40.0 rect_min_size = Vector2( 215, 40 ) size_flags_horizontal = 2 size_flags_vertical = 2 custom_styles/hover = SubResource( 19 ) custom_styles/pressed = SubResource( 20 ) custom_styles/focus = SubResource( 21 ) custom_styles/disabled = SubResource( 22 ) custom_styles/normal = SubResource( 23 ) toggle_mode = true [node name="icon" type="TextureRect" parent="playergroupdetails/Panel/TabContainer/Items/VBoxContainer/Button"] anchor_right = 1.0 anchor_bottom = 1.0 margin_right = -175.0 rect_min_size = Vector2( 40, 40 ) size_flags_horizontal = 2 size_flags_vertical = 2 expand = true stretch_mode = 5 [node name="amount" type="Label" parent="playergroupdetails/Panel/TabContainer/Items/VBoxContainer/Button"] margin_left = 38.0 margin_top = 19.0 margin_right = 53.0 margin_bottom = 39.0 size_flags_horizontal = 2 size_flags_vertical = 0 [node name="name" type="Label" parent="playergroupdetails/Panel/TabContainer/Items/VBoxContainer/Button"] margin_left = 75.0 margin_top = 11.0 margin_right = 205.0 margin_bottom = 31.0 size_flags_horizontal = 2 size_flags_vertical = 0 clip_text = true [node name="Spells" type="ScrollContainer" parent="playergroupdetails/Panel/TabContainer"] visible = false anchor_right = 1.0 anchor_bottom = 1.0 margin_left = 10.0 margin_top = 40.0 margin_right = -10.0 margin_bottom = -11.0 rect_min_size = Vector2( 215, 0 ) size_flags_horizontal = 3 size_flags_vertical = 3 scroll_horizontal_enabled = false scroll_vertical_enabled = false [node name="VBoxContainer" type="VBoxContainer" parent="playergroupdetails/Panel/TabContainer/Spells"] margin_right = 215.0 rect_min_size = Vector2( 215, 0 ) size_flags_horizontal = 2 size_flags_vertical = 2 custom_constants/separation = 0 [node name="Button" type="Button" parent="playergroupdetails/Panel/TabContainer/Spells/VBoxContainer"] visible = false margin_right = 215.0 margin_bottom = 40.0 rect_min_size = Vector2( 215, 40 ) size_flags_horizontal = 2 size_flags_vertical = 2 custom_styles/hover = SubResource( 19 ) custom_styles/pressed = SubResource( 20 ) custom_styles/focus = SubResource( 21 ) custom_styles/disabled = SubResource( 22 ) custom_styles/normal = SubResource( 23 ) toggle_mode = true [node name="name" type="Label" parent="playergroupdetails/Panel/TabContainer/Spells/VBoxContainer/Button"] margin_left = 15.0 margin_top = 10.0 margin_right = 155.0 margin_bottom = 30.0 size_flags_horizontal = 2 size_flags_vertical = 0 text = "SpellName" clip_text = true [node name="cost" type="Label" parent="playergroupdetails/Panel/TabContainer/Spells/VBoxContainer/Button"] margin_left = 160.0 margin_top = 11.0 margin_right = 200.0 margin_bottom = 31.0 size_flags_horizontal = 2 size_flags_vertical = 0 text = "1" align = 2 [node name="closegroup" type="Button" parent="playergroupdetails"] anchor_left = 1.0 anchor_top = 1.0 anchor_right = 1.0 anchor_bottom = 1.0 margin_left = -750.0 margin_top = -69.0 margin_right = -575.0 margin_bottom = -27.0 remove lines 257-272: [sub_resource type="StyleBoxTexture" id=30] texture = ExtResource( 44 ) region_rect = Rect2( 0, 0, 150, 18 ) margin_left = 5.0 margin_right = 5.0 margin_top = 5.0 margin_bottom = 5.0 [sub_resource type="StyleBoxTexture" id=31] texture = ExtResource( 45 ) region_rect = Rect2( 0, 0, 150, 18 ) margin_left = 5.0 margin_right = 5.0 margin_top = 5.0 margin_bottom = 5.0 replace line 253 with: [sub_resource type="StyleBoxTexture" id=30] replace line 247 with: [sub_resource type="DynamicFont" id=29] replace line 241 with: [sub_resource type="DynamicFont" id=28] replace line 235 with: [sub_resource type="DynamicFont" id=27] replace line 231 with: [sub_resource type="StyleBoxTexture" id=26] replace lines 226-229 with: margin_left = 5.0 margin_right = 5.0 margin_top = 5.0 margin_bottom = 5.0 replace line 223 with: [sub_resource type="StyleBoxTexture" id=25] replace line 215 with: [sub_resource type="StyleBoxTexture" id=24] add lines after 207: [sub_resource type="StyleBoxTexture" id=23] remove lines 203-204: [sub_resource type="StyleBoxTexture" id=20] replace line 195 with: [sub_resource type="StyleBoxTexture" id=20] replace line 187 with: [sub_resource type="StyleBoxTexture" id=19] add lines after 183: texture = ExtResource( 40 ) region_rect = Rect2( 0, 0, 500, 500 ) margin_left = 15.0 margin_right = 15.0 margin_top = 15.0 margin_bottom = 15.0 [sub_resource type="StyleBoxTexture" id=18] replace line 1 with: [gd_scene load_steps=120 format=2] shopinventory.gd changed max button to set amount to max purchasable or sellable(v2a) replace line 417 with: if isBuying: $amountselect/SpinBox.value = floor(globals.resources.gold / selecteditem.get_meta('price')) else: $amountselect/SpinBox.value = int(selecteditem.get_node('number').text) fixed incrementing with +5 and +10 buttons when current value is 1 (v2a), simplied behavior(v2b) replace lines 412-413 with: $amountselect/SpinBox.value += 10 replace lines 406-407 with: $amountselect/SpinBox.value += 5 added updated text when amount is updated(enter or tab will cause update when typing new value)(v2a), improved text(v2b) add function after 402: func _on_SpinBox_value_changed(value): var text = "" var item = selecteditem.get_meta('item') var amount = $amountselect/SpinBox.value if isBuying: var cost = getcost(item, 'buy') text += "You will purchase [color=green]" + item.name + "[/color] for " + str(cost) + " gold each. " text += "\nCost for [color=yellow]" + str(amount) + "[/color] is [color=yellow]" + str(cost*amount) + "[/color] gold" else: var cost = getcost(item, 'sell') text += "You will sell [color=green]" + item.name + "[/color] for " + str(cost) + " gold each. " text += "\nOffer for [color=yellow]" + str(amount) + "[/color] is [color=yellow]" + str(cost*amount) + "[/color] gold" $amountselect/RichTextLabel.bbcode_text = text changed amount selection pop-up to support buying and selling(v2a) replace lines 344-384 with: if isBuying: if amount*price > globals.resources.gold: globals.main.infotext("Not enough gold",'red') return if state == 'backpack' && item.has('weight') && globals.state.calculateweight().currentweight + amount*item.weight > globals.state.calculateweight().maxweight: globals.main.infotext("Not enough carry capacity",'red') return elif state == 'backpack' && (item.code == 'food' || (item.code.find('teleport') >= 0 && item.code != 'teleportseal')): globals.main.infotext("This item can't be purchased for backpack",'red') return if item.type != 'gear': if state != 'backpack': item.amount += amount else: if globals.state.backpack.stackables.has(item.code): globals.state.backpack.stackables[item.code] += amount else: globals.state.backpack.stackables[item.code] = amount else: var counter = amount while counter >= 1: var tmpitem = globals.items.createunstackable(item.code) if state != 'backpack': globals.state.unstackables[str(tmpitem.id)] = tmpitem else: globals.state.unstackables[str(tmpitem.id)] = tmpitem tmpitem.owner = 'backpack' counter -= 1 globals.main.infotext("Obtained: " + item.name, 'green') if item.code in ['food'] || item.type == 'quest': globals.items.call(item.effect, item) elif item.code.find('teleport') >= 0 && item.code != 'teleportseal': globals.items.call(item.effect, item) selecteditem = null else: globals.resources.gold -= price*amount clearitems() if state == 'inventory': itemsinventory() elif state == 'backpack': calculateweight() itemsbackpack() else: if amount > int(selecteditem.get_node('number').text): globals.main.infotext("Not enough items",'red') return globals.resources.gold += price*amount if state == 'inventory' or (item.has('owner') && item.owner != null): if item.has('id'): var itemarray = selecteditem.get_meta('itemarray') for i in range(amount): var tempitem = itemarray[itemarray.size()-1] globals.state.unstackables.erase(tempitem.id) itemarray.erase(tempitem) selecteditem.get_node('number').set_text(str(itemarray.size())) if itemarray.size() <= 0: selecteditem.visible = false selecteditem.queue_free() calculateweight() else: item.amount -= amount selecteditem.get_node('number').set_text(str(item.amount)) if item.amount <= 0: selecteditem.visible = false selecteditem.queue_free() elif state == 'backpack': globals.state.backpack.stackables[item.code] -= amount if globals.state.backpack.stackables.has(item.code): selecteditem.get_node('number').set_text(str(globals.state.backpack.stackables[item.code])) else: selecteditem.visible = false selecteditem.queue_free() calculateweight() changed text when buying, added reset of amount to 1 (v2a), improved text(v2b) replace lines 331-336 with: isBuying = true var item = button.get_meta('item') var cost = getcost(item, 'buy') var text = "You will purchase [color=green]" + item.name + "[/color] for " + str(cost) + " gold each. " text += "\nCost for [color=yellow]1[/color] is [color=yellow]" + str(cost) + "[/color] gold" selecteditem = button $amountselect/SpinBox.value = 1 $amountselect/RichTextLabel.bbcode_text = text $amountselect.popup() changed selling button to open amount selection pop-up, added reset of amount to 1 (v2a), improved text(v2b) replace lines 300-328 with: isBuying = false var item = button.get_meta('item') var cost = getcost(item, 'sell') var text = "You will sell [color=green]" + item.name + "[/color] for " + str(cost) + " gold each. " text += "\nOffer for [color=yellow]1[/color] is [color=yellow]" + str(cost) + "[/color] gold" selecteditem = button $amountselect/SpinBox.value = 1 $amountselect/RichTextLabel.bbcode_text = text $amountselect.popup() handled error related to unstackable items leftover from mods(v4) replace lines 261-271 with: if globals.itemdict.has(item.code): if globals.itemdict[item.code].type != 'gear': cost = item.cost*variables.sellingitempricemod if merchant == true: cost *= 1.25 if item.type == 'potion' && globals.state.spec == "Alchemist": cost *= 2 else: var itemtype = globals.itemdict[item.code] cost = itemtype.cost*variables.sellingitempricemod if item.has('enchant') && item.enchant != '': cost = cost*variables.enchantitemprice changed function used for loading item icons to support non-imported images(v3b) replace lines 241-244 with: if item.icon != null: newbutton.get_node("icon").set_texture(globals.loadimage(item.icon)) replace line 211 with: button.get_node("icon").set_texture(globals.loadimage(i[0].icon)) added sorting for equipable items listed for sale(v2a) add line after 191: array.sort_custom(load("res://files/inventory.gd").new(), 'sortgear') changed function used for loading item icons to support non-imported images(v3b) replace line 147 with: button.get_node("icon").set_texture(globals.loadimage(i[0].icon)) added sorting for equipable items listed for sale(v2a) add line after 125: array.sort_custom(load("res://files/inventory.gd").new(), 'sortgear') changed the shops to show everything by default(v3d) add line after 47: selectcategory(get_node("everything")) added variable to track whether amount select is for buying or selling(v2a) add line after 3: var isBuying = true exploration.gd simplified the code tracking of location for slave guilds/markets, which also fixes an obscure bug related to Slavers and Umbra(v4) remove line 1861: outside.sellslavelocation = 'umbra' hide combat group panel when viewing slaves at Umbra(v2) add line after 1859: outside.get_node("playergrouppanel/VBoxContainer").visible = false add line after 1856: outside.get_node("playergrouppanel/VBoxContainer").visible = false simplified the code tracking of location for slave guilds/markets, which also fixes an obscure bug related to Slavers and Umbra(v4) remove line 1844: outside.location = 'umbra' remove line 1753: outside.location = 'frostford' remove line 1548: outside.location = 'amberguard' remove line 1373: outside.location = 'gorn' minor changes to text about persons defeated or rescued, removed unused variable(v3) replace line 1302 with: text = "As you are about to move on, the $race $child that you have rescued appeals to you. $His name is $name and $he's very thankful for your help. $name wishes to repay you somehow. " remove line 1297: var rewardslavename replace line 1266 with: text += "You undress your prisoner and without further hesitation mercilessly rape the " + orgyarray[0].dictionary("$race $child") + ". \n" remove line 1233: rewardslavename = defeated.names[i] replace line 1228 with: text += defeated.units[i].dictionary("You have released the $race $child and set $him free.\n") replace line 1226 with: text += defeated.units[i].dictionary("You have left the $race $child alone.\n") fixed race URL in defeated person's description(v3e) add line after 1188: get_tree().get_current_scene().get_node("MainScreen/slave_tab").person = person changed function used for loading item icons to support non-imported images(v3b) replace line 1102 with: newbutton.get_node("image").set_texture(globals.loadimage(i.icon)) replace line 1072 with: newbutton.get_node("image").set_texture(globals.loadimage(i.icon)) fixed possibility of uncivilized tamers(v3f) add lines after 1019: if person.spec == 'tamer': person.spec = null added handling for enchanted rewardpool items(currently no such items)(v3f) add lines after 932: if enchant: globals.items.enchantrand(tempitem) add lines after 923: var enchant = false if i.ends_with("+"): enchant = true i = i.replace("+","") hide player group panel when viewing slavers' slaves(v3e) simplified the code tracking of location for slave guilds/markets, which also fixes an obscure bug related to Slavers and Umbra(v4) add line after 732-735: outside.get_node("playergrouppanel/VBoxContainer").visible = false globals.main.get_node("outside").slavearray = enemygroup.captured globals.main.get_node("outside").slaveguildslaves('slavers') changed how mindread button updates when selling slaves to fix issues with slavers and mana cost when player is Mage(v4) add line after 719: outside.mindread = false added update to combat party panel after failed attempt to open treasure chest(v2) add line after 599: outside.playergrouppanel() add line after 578: outside.playergrouppanel() fixed duplication of event enemies when exploring deeper regions(v4) replace line 418 with: if deeperregion && (enemyname == null || enemyname.find("guards") >= 0): fixed encountered persons occasionally having the wrong number of skill points(v3d) replace lines 391-403 with: var skillpoints = abs(level-person.level)*variables.skillpointsperlevel while skillpoints > 0 && statdict.size() > 0: var tempstat = statdict[randi()%statdict.size()] #slaves can be constructed with levels greater than they will recieve for the region of encounter if person.level < level: if randf() <= 0.2: person.skillpoints += 1 elif person.stats[globals.maxstatdict[tempstat].replace('_max',"_base")] >= person.stats[globals.maxstatdict[tempstat]]: statdict.erase(tempstat) continue else: person.stats[globals.maxstatdict[tempstat].replace('_max',"_base")] += 1 elif person.stats[globals.maxstatdict[tempstat].replace('_max',"_base")] <= 0: statdict.erase(tempstat) continue else: person.stats[globals.maxstatdict[tempstat].replace('_max',"_base")] -= 1 skillpoints -= 1 if skillpoints > 0 && statdict.empty(): if person.level < level: person.skillpoints += skillpoints else: person.skillpoints = max(person.skillpoints - skillpoints, 0) person.level = level changed enemy monster level estimates to be at least 30% higher when in deeper regions to reflect stat bonuses(v3e) changed enemy person level estimates to be the average of enemy's levels rather than just the first enemy's level(v3e) changed enemy level estimates to handle mixed enemy groups(don't think any exist)(v3f) replace line 374 with: var total = 0 for i in enemygroup.units: if i.capture != null: total += i.capture.level elif deeperregion: total += ceil(i.level * 1.3) else: total += i.level text += "\nEstimated level: " + str(max(1,round(total/enemygroup.units.size()) + round(rand_range(-1,1)))) changed minimum for enemy number estimates to prevent 4 enemies being estimated as 2(v3f) replace line 373 with: text = "Estimate number: " + str(max(round(enemygroup.units.size() + rand_range(-2,2)),3)) fixed exploring deeper regions increasing enemy awareness, which increases possibility of ambushes(v3) replace line 273 with: elif scoutawareness < enemyawareness: fixed being able to progress quests without having the necessary slave(v4) replace line 133 with: for i in globals.slaves: if i.unique == 'Cali': array.append({name = "Find Cali's village",function = 'event',args = 'calireturnhome'}) break simplified the code tracking of location for slave guilds/markets, which also fixes an obscure bug related to Slavers and Umbra(v4) remove line 79: outside.currentzone = zone added additional reset for deeperregion when arriving at a non-combat zone(v4) add line after 58: deeperregion = false simplified the code tracking of location for slave guilds/markets, which also fixes an obscure bug related to Slavers and Umbra(v4) remove line 56: outside.location = zone.code jobs&specs.gd added a minimum limit to maid cleaning so that negative stats don't make a mess(v3e) replace line 972 with: var temp = 5.5 + max(0, person.sagi+person.send)*6 fixed text for gold from market job(v3b) replace line 800 with: text += "$He returned with [color=yellow]"+str(gold)+"[/color] gold by the end of day.\n" fixed returned value from market job when no change in amount of supplies(v3b) add lines after 795: else: supplySold = 0 changed grade-based scaling of gold from market job so that lower grade slaves are more productive than before(v3b) replace line 783 with: gold = round(gold * min(0.10 * (globals.originsarray.find(person.origins) + 7), 1) * bonus) fixed negative food from foraging and hunting(v3f) replace line 578 with: food = round(min(food, max(person.sstr+person.send, -1)*30+40)) replace line 558 with: food = min(food, max(person.sstr+person.send, -1)*20+25) changed "away" tag for slaves requiring vacation for level-up(v2) add line after 392: person.away.at = 'vacation' spells.gd fixed stress fear spell giving stress reduction with high magic affinity replace line 342 with: person.stress += max(5, 20-caster.smaf*3) minor fix to text of entrancement spell(v3) replace line 333 with: text = "It seems like $name is already entranced. " changed "away" tag for dream spell(v2) add line after 306: person.away.at = 'rest' minor fix to text of sedation and heal spells(v3) replace line 298 with: text = "It seems like $name was not injured in first place. " replace line 274 with: text = "You cast Sedation spell on $name, but it appears $he is already under its effect. " person.gd changed slave list obedience icon color scaling to not be a percent of max, and slight adjustment to match text colors(v3e) replace line 606 with: elif stats.obed_cur > 40: replace line 604 with: if stats.obed_cur > 80: fixed effects modifying energy change or lust growth not working until progress is loaded from save(v3d) replace line 496 with: stats.lust_cur = clamp(stats.lust_cur + difference*(1 + stats.lust_mod/100.0),stats.lust_min,stats.lust_max) replace line 474 with: stats.energy_cur = clamp(stats.energy_cur + difference*(1 + stats.energy_mod/100.0), 0, stats.energy_max) added conversion of experience to float to ensure no integer division can occur(no known cases)(v3d) replace line 282 with: realxp += max(float(difference)/max(level,1),1) added limits to slave's role preference(v2a) add function after 252: func asser_set(value): asser = clamp(value, 0, 100) replace line 121 with: var asser = 0 setget asser_set constmodinstall.gd moved the updating of the constants mod to the installer rather than the mod, which should resolve issues related to updating the mod(v2c) also the mod no longer deletes user's values updated version number(v4) replace lines 10-16 with: var modsubfolder = globals.modfolder + 'Constants/' if dir.dir_exists(modsubfolder): if !overwrite: #Check and overwrite this mod if updated var config = ConfigFile.new() config.load(modsubfolder + 'data.ini') if config.get_value('main', 'modversion') != modversion: overwrite = true if overwrite: for i in globals.dir_contents(modsubfolder): if i.find('storedvariables') == -1: dir.remove(i) else: return replace line 6 with: var modversion = '0.4' constantsmoddata/mainmenu.gd changed constants mod init 1 line lower to give precedence to the constants mod installer(v2c) replace line 2 with: constantsmoddata/constantsmod.gd moved the updating of the constants mod to the installer rather than the mod, which should pre-emptively resolve issues related to updating the mod(v2c) overhauled the entire file for (v4), thus no line by line report added support for changing variables in files other than variables.gd, which will even allow customization of variables in other mods added support for changing values with complex paths such as being inside several layers of objects, arrays, and dictionaries fixed support for changing the contents of arrays and dictionaries, though this comes with many limitations for safety added the grouping of variables into categories for organization added color changes to indicate custom values and those that are outside of the optional min/max recommendations added the ability to reset selected variables to their default values changed the file format for storing custom values to json, existing files should update seemlessly reorganized the mod's data storage for efficiency, added basic data proofreading and error reporting adjusted the GUI sizes and positions theme.tres added slight tint to text when hovering mouse over checkbox(v2c) replace line 246 with: CheckBox/colors/font_color_hover = Color( 0.882353, 1, 0.823529, 1 ) fixed black line that appears when hovering mouse over checkbox, added slightly larger shift right to text(v2c) replace line 68 with: [sub_resource type="StyleBoxTexture" id=9] content_margin_left = 2.0 options.tscn a lot of minor changes to gui to fix pixel alignments, sizes, and overlaps(v2c) replace lines 380-384 with: margin_left = 823.0 margin_top = -13.0 margin_right = 544.0 margin_bottom = 317.0 rect_rotation = 90.0 replace lines 327-329 with: margin_top = 276.0 margin_right = 240.0 margin_bottom = 296.0 replace lines 315-317 with: margin_top = 300.0 margin_right = 253.0 margin_bottom = 316.0 replace lines 305-307 with: margin_top = 230.0 margin_right = 259.0 margin_bottom = 250.0 replace lines 294-296 with: margin_top = 254.0 margin_right = 253.0 margin_bottom = 270.0 replace lines 283-285 with: margin_top = 174.0 margin_right = 452.0 margin_bottom = 201.0 replace lines 272-274 with: margin_top = 147.0 margin_right = 175.0 margin_bottom = 174.0 replace lines 262-264 with: margin_top = 174.0 margin_right = 210.0 margin_bottom = 201.0 replace lines 251-253 with: margin_top = 120.0 margin_right = 295.0 margin_bottom = 147.0 replace lines 240-242 with: margin_top = 93.0 margin_right = 365.0 margin_bottom = 120.0 replace lines 210-212 with: margin_top = 66.0 margin_right = 480.0 margin_bottom = 93.0 replace lines 200-202 with: margin_top = 66.0 margin_right = 90.0 margin_bottom = 93.0 replace lines 190-194 with: margin_left = 823.0 margin_top = -13.0 margin_right = 544.0 margin_bottom = 317.0 rect_rotation = 90.0 replace lines 167-170 with: margin_left = 20.0 margin_top = 124.0 margin_right = 264.0 margin_bottom = 151.0 replace lines 151-153 with: margin_top = 175.0 margin_right = 581.0 margin_bottom = 192.0 replace lines 134-136 with: margin_top = 125.0 margin_right = 581.0 margin_bottom = 142.0 replace lines 123-125 with: margin_top = 51.0 margin_right = 481.0 margin_bottom = 89.0 replace lines 112-115 with: margin_left = 20.0 margin_top = -462.0 margin_right = 205.0 margin_bottom = -435.0 replace lines 102-104 with: margin_top = 61.0 margin_right = 609.0 margin_bottom = 81.0 replace lines 90-93 with: margin_left = 20.0 margin_top = 178.0 margin_right = 264.0 margin_bottom = 205.0 replace lines 76-79 with: margin_left = 20.0 margin_top = 151.0 margin_right = 264.0 margin_bottom = 178.0 replace lines 66-69 with: margin_left = 20.0 margin_top = 97.0 margin_right = 264.0 margin_bottom = 124.0 replace lines 56-59 with: margin_left = 20.0 margin_top = 70.0 margin_right = 322.0 margin_bottom = 97.0 replace lines 47-51 with: margin_left = 823.0 margin_top = -13.0 margin_right = 544.0 margin_bottom = 317.0 rect_rotation = 90.0 replace lines 26-28 with: margin_left = 5.0 margin_top = 12.0 margin_right = 835.0 statstab.gd fixed minor display bug after granting slave a vacation for level up(v4) replace line 427 with: if command != 'vacation': get_parent().slavetabopen() fixed errors when casting spell on slave or teaching slave ability without selecting one first(v2c) add line after 183: get_node("selectspellpanel/spellusebutton").set_disabled(true) add line after 54: get_node("trainingabilspanel/abilityconfirm").set_disabled(true) modpanel.gd added button to close mod/error report panel without closing game(v3e) add lines at end of file: func _on_continuebutton_pressed(): $restartpanel.hide() added error reporting to opening the mod folder(v3e) replace lines 447-449 with: retCode = OS.shell_open(modfolder.replace("user:/", OS.get_user_data_dir())) handleError("OS shell opening " + str(modfolder.replace("user:/", OS.get_user_data_dir())), retCode) else: retCode = OS.shell_open(modfolder) handleError("OS shell opening " + str(modfolder), retCode) fixed errors caused by untagged changes at very start of mod file, changes containing a mod tag will not use that tag(v3) replace line 410 with: return current_match.get_end() fixed cases of a change causing a subsequent change to be skipped(v3) remove line 408: offset = new_offset + 1 removed code that literally does nothing, added error message if incorrect tag is used(v3c), updated(v3e) replace line 407 with: handleError("ERROR: '" + str(next_tag.get_string(1)) + "' tag not supported.", ERR_BUG) remove line 404: pass changed RemoveFrom changes to use replaceOnce(v3c) replace line 402 with: temp_mod_scripts[key] = replaceOnce(temp_mod_scripts[key], nested_match, new_string.join("\n")) fixed check for out of bounds RemoveFrom changes(v3) replace line 400 with: if param < new_string.size(): changed get_string to use group names for new regexs(v3c) replace line 397 with: if(current_match.get_string("header") == nested_match.get_string("header")): changed RemoveFrom indices to start at 0 instead of 1, now matches AddTo index. added min limit of 0 to indices(v3) replace lines 394-395 with: var param = max(1, next_tag.get_string(2).to_int() + 1) var param_2 = max(1, next_tag.get_string(3).to_int() + 1) changed get_string to use group names for new regexs, changed AddTo changes to use replaceOnce(v3c) fixed mult-line arrays, fixed left behind '=' from mult-line var, fixed -1 index for AddTo(also, multi-line variables are properly limited)(v3c) removed signals from AddTo as they have not body group, ONREADY combined into VAR(v3c) replace 353-391 with: if(current_match.get_string("header") == nested_match.get_string("header")): var pool_string = nested_match.get_string().split("\n") if which_operation in ["FUNC",'CLASS']: if param == -1 || param >= pool_string.size(): pool_string.remove(pool_string.size() - 1) for i in current_match.get_string("body").split("\n"): pool_string.append(i) else: for i in current_match.get_string("body").split("\n"): pool_string.insert(param, i) param += 1 temp_mod_scripts[key] = replaceOnce(temp_mod_scripts[key], nested_match, pool_string.join("\n")) elif which_operation == "VAR": var match_stripped = current_match.get_string("body") if match_stripped.find('\n') < match_stripped.length() - 1: #if matching brackets are found, strips the first and last brackets var chrIdx1a = match_stripped.find("{") var chrIdx1b = match_stripped.find("[") if chrIdx1a != -1 && (chrIdx1b == -1 || chrIdx1a < chrIdx1b) : var chrIdx2 = match_stripped.find_last("}") if chrIdx2 >= 0: match_stripped.erase(chrIdx2, 1) match_stripped = match_stripped.right(chrIdx1a + 1) elif chrIdx1b != -1: var chrIdx2 = match_stripped.find_last("]") if chrIdx2 >= 0: match_stripped.erase(chrIdx2, 1) match_stripped = match_stripped.right(chrIdx1b + 1) if pool_string.size() > 2: if param == -1 || param > pool_string.size() - 2: param = pool_string.size() - 2 elif param == -1 || param > pool_string.size() - 1: param = pool_string.size() - 1 for i in match_stripped.split("\n", false): if i.strip_edges() != "": pool_string.insert(param, i) param += 1 temp_mod_scripts[key] = replaceOnce(temp_mod_scripts[key], nested_match, pool_string.join("\n")) #else operation not supported added min limit of -1 to AddTo index(v3) replace line 348 with: var param = max(0, next_tag.get_string(2).to_int() + 1) added an empty line between each untagged change with no match to existing code(v3) replace line 340 with: temp_mod_scripts[key] = temp_mod_scripts[key] + "\n\n" + current_match.get_string() changed untagged changes to use replaceOnce(v3c) replace line 337 with: temp_mod_scripts[key] = replaceOnce(temp_mod_scripts[key], nested_match, current_match.get_string()) changed get_string to use group names for new regexs(v3c) replace line 336 with: if(current_match.get_string("header") == nested_match.get_string("header")): fixed errors caused by untagged changes at very start of mod file, changes containing a mod tag will not use that tag(v3) remove lines 326-327: if new_offset != 0 : new_offset = new_offset + current_match.get_string().length() added error reporting to regex compiling, probably pointless though(v3e) replace line 317 with: retCode = next_func.compile(regex_string_dictionary[i]) handleError("Compiling regex " + str(i), retCode) replace line 307 with: retCode = full_tag.compile(tag_regex) handleError("Compiling tag regex", retCode) changed tag regex to better match expectations(v3c) replace line 302 with: var tag_regex = "<(\\w+)(\\h+\\-?\\d+)?(\\h+\\-?\\d+)?>" added untabbed leading comments to all code regexs, removed trailing untabbed comments from functions and classes.(v3) changed variable definition regex to match variables without initial assignment(=) and only match file-scoped variables(no longer matches all variables with same name).(v3) added file-scoped constant definition regex. added multi-line definitions for onready variables to regex.(v3) changed multi-line variable definitions to not include all trailing blank lines.(v3) removed requirement for non-empty functions and classes, which accidentally resulted in problems for RemoveFrom(v3a) simplified func and class regexs, combined all variable variants into one regex, added support for more keywords(v3c) added group names since combining regexs unevenly changed the group numbers, other minor fixes(v3c) replace lines 295-300 with: regex_string_dictionary["FUNC"] = "(#.*\\R)*(?
(?((\\t.*|#.*)?\\R)*(\\t+\\S.*(\\R|\\Z)))?" regex_string_dictionary["VAR"] = "(#.*\\R)*(?
(?(\\h*:?=\\h*[\\{\\[](.*|[\\S\\s]*?\\R)[\\}\\]].*|.*)(\\R|\\Z))" regex_string_dictionary["SIGN"] = "(#.*\\R)*(?
(?(?((\\t.*|#.*)?\\R)*(\\t+\\S.*(\\R|\\Z)))?" added function to replace the target string with new text only once using known position, increases efficiency and avoids errors(v3c) add function after line 292 func replaceOnce(strFile, matchTarget, newText): strFile.erase(matchTarget.get_start(), matchTarget.get_string().length()) return strFile.insert(matchTarget.get_start(), newText) added print statement when the modding system has an error, which contains the end position. error now results in skipping the rest of file(v3c), updated error reporting(v3e) replace line 291 with: var newOffset = apply_next_element_to_dictionary(file_name, string, offset) if newOffset == null: var lineNum = 1 newOffset = -1 var temp while true: temp = string.find('\n', newOffset + 1) if temp == -1 || temp > offset: break else: newOffset = temp lineNum += 1 handleError("WARNING: error occurred while modding file " + str(file_name) + ", skipped rest of file. Ended on line: " + str(lineNum) + ", Column: " + str(offset - newOffset), ERR_BUG) return else: offset = newOffset added error reporting and handling to file operations(v3e) fixed a file path operation which would break mods with the mod's folder name in other parts of the path(v3e) replace lines 286-288 with: retCode = file.open(file_name, File.READ) if retCode == OK: temp_mod_scripts[file_name] = file.get_as_text() file.close() else: handleError("Reading file " + str(file_name), retCode) replace lines 277-279 with: retCode = modfile.open(i, File.READ) if retCode == OK: mod[i.replace(string, filedir)] = modfile.get_as_text() modfile.close() else: handleError("Reading mod script " + str(i), retCode) remove line 273: string = string.replace(modfolder, '') added recording of mod script files that do not match game files(v3e) add lines after 268: if !file_dictionary.has(file): logUnmatched.append(str(file.replace(filedir, mod))) added error reporting and handling to file operations(v3e) replace lines 260-262: retCode = core_file.open(i, File.WRITE) if retCode == OK: core_file.store_string(temp_mod_scripts[i]) core_file.close() else: handleError("Modding file " + str(i), retCode) added error reporting to the mod system which appears after mods are applied or the mod panel is opened/refreshed(v3e) added reporting of mod script files that do not match game files(v3e) replace line 255 with: displayReport() add functions after 244: func handleError(msg, code): if code != OK: logErrors.append("ERROR: " + msg + " (" + globals.errorText[code] + ")") globals.printErrorCode(msg, code) func displayReport(afterMod = true): var text if afterMod: text = "Mod list has been changed. Game must close for changes to take effect." else: text = "Errors in the mod system have been detected." if logErrors.size() == 0: text += "\n\n[color=green]No errors recorded.[/color]" else: text += "\n\n[color=red]The following errors were recorded:[/color]\n" + logErrors.join('\n') logErrors = PoolStringArray() if logUnmatched.size() > 0: text += "\n\nThe following mod scripts did not match an existing file:\n" + logUnmatched.join('\n') logUnmatched = PoolStringArray() $restartpanel/RichTextLabel.bbcode_text = text $restartpanel.show() added error reporting and handling to file operations(v3e) replace lines 207-210: var text = '' retCode = file.open(modfolder + mod + '/info.txt', File.READ) if retCode == OK: text = file.get_as_text() file.close() else: handleError("Reading file " + str(modfolder + mod + '/info.txt'), retCode) simplified the mod sorting function and added explicit ordering for some cases(v3c), updated(v3e) replace lines 194-204 with: var index1 = loadorder.find(first) var index2 = loadorder.find(second) if index1 == index2: return first < second if index1 < index2: return index1 != -1 return index2 == -1 added error report when opening/refreshing the mod panel(v3e) add lines after 191: if logErrors.size() > 0: displayReport(false) simplified mod list sorting by shortening the folder paths earlier(v3e) remove line 176: i = i.replace(modfolder,"") replace line 173 with: array.append(i.replace(modfolder,"")) changed tooltip for mod folder button to contain an explanation(v3e) replace line 165 with: $modfolder.hint_tooltip = "Select new location for mod folder. Current location: \n" + modfolder added error reporting and handling to file operations(v3e) replace lines 154-159 with: retCode = backup.open(i.replacen(filedir, backupdir), File.READ) if retCode == OK: var file_string = backup.get_as_text() backup.close() retCode = backup.open(i, File.WRITE) if retCode == OK: backup.store_string(file_string) backup.close() else: handleError("Resetting file " + str(i), retCode) else: handleError("Reading backup file " + str(i.replacen(filedir, backupdir)), retCode) replace lines 137-145 with: if !backup.file_exists(nameB): retCode = file.open(i, File.READ) if retCode == OK: retCode = backup.open(nameB, File.WRITE) if retCode == OK: backup.store_string(file.get_as_text()) backup.close() else: handleError("Writing backup file " + str(nameB), retCode) file.close() else: handleError("Reading file " + str(i), retCode) retCode = file.open(backupdir + "/version", File.WRITE) if retCode == OK: file.store_line(str(globals.gameversion)) file.close() else: handleError("Writing version file", retCode) moved backup directory creation into the appropriate function(v3e) add lines after 135: var nameB = i.replacen(filedir, backupdir) var baseDir = nameB.get_base_dir() if !dir.dir_exists(baseDir): retCode = dir.make_dir_recursive(baseDir) handleError("Making backup directory " + str(baseDir), retCode) added error reporting and handling to file operations(v3e) replace lines 132-133 with: if dir.dir_exists(backupdir): for i in globals.dir_contents(backupdir): retCode = dir.remove(i) handleError("Deleting file " + str(i), retCode) replace line 121 with: retCode = config.save(fileName) handleError("Saving config file " + fileName, retCode) replace line 118 with: var fileName = str(modfolder) + "FileOrder.ini" if file.file_exists(fileName): retCode = config.load(fileName) handleError("Opening config file " + fileName, retCode) removed uneeded blank lines(v3c) remove line 112 remove lines 105-109 added error reporting and handling to file operations(v3e) replace lines 92-96 with: if !file.file_exists(modfolder + "FileOrder.ini"): return var config = ConfigFile.new() var retCode = config.load(modfolder + "FileOrder.ini") if retCode == OK: loadorder = config.get_value("Mods", "LoadOrder", []) activemods = config.get_value("Mods", "ActiveMods", []) else: handleError("Opening config file " + str(modfolder + "FileOrder.ini"), retCode) replace lines 70-79 with: retCode = dir.make_dir(modfolder) handleError("Making mod directory " + str(modfolder), retCode) retCode = dir.open(modfolder) if retCode == OK: retCode = dir.list_dir_begin(true) if retCode == OK: var file_name = dir.get_next() while file_name != "": if dir.current_is_dir() && !file_name in ['.','..',null]: array.append(modfolder + file_name) file_name = dir.get_next() else: handleError("Scanning mod directory " + str(modfolder), retCode) else: handleError("Opening mod directory " + str(modfolder), retCode) return array remove line 66: var target = modfolder replace lines 57-59 with: var text = '' retCode = file.open(backupdir + "/version", File.READ) if retCode == OK: text = file.get_as_text() file.close() else: handleError("Reading version file", retCode) removed uneeded blank lines(v3c), removed code that served no purpose(v3e) added error reporting and handling to file operations(v3e) replace lines 34-49 with: retCode = file.open(i+'/info.txt', File.WRITE) if retCode == OK: file.store_line("There's no information on this mod.") file.close() else: handleError("Creating default info.txt", retCode) replace line 32 with: for i in scanfolder(): moved backup directory creation into the appropriate function(v3e) replace lines 26-30 with: for i in files: #collects file_dictionary data if i.find(".gd") != -1: add file scoped variables for error reporting, remove unused file scoped variables(v3e) add lines after 13: var logErrors = PoolStringArray() var logUnmatched = PoolStringArray() var retCode #lazy def to avoid many def remove line 7: var mods_dictionary = {} #mod folder data remove lines 3-4: var run_once = false newsexsystem.gd fixed condition preventing the inclusion of text when a woman does not enjoy homosexual interactions(v3) replace line 1399 with: if (!character.person.traits.has('Homosexual') && !character.person.traits.has("Bisexual")) && character.sex != 'male' && partner.sex != 'male' && partnerside == 'givers': items.gd added partial support for items that add abilities(v4) add lines after 1667: func toggleStrNeg(value): if value.ends_with('-'): return value.erase(value.length()-1, 1) else: return value + '-' replace line 1660 with: if typeof(i.effectvalue) == TYPE_STRING: call(i.effect, toggleStrNeg(i.effectvalue)) else: call(i.effect, -i.effectvalue) added max health update after un-equiping an item(v3d) add line after 1647: person.health += 0 added partial support for items that add abilities(v4) replace line 1647 with: if typeof(i.effectvalue) == TYPE_STRING: call(i.effect, toggleStrNeg(i.effectvalue)) else: call(i.effect, -i.effectvalue) removed unecessary dictionary function calls(already called in Mansion.gd) and some minor text changes(v3) replace line 1332 with: var text = "$name's revealing clothes teach $him how to better present $himself to others. \n" replace line 1326 with: var text = "$name's miko outfit helps $him to collect $his thoughts and calm down.\n" replace line 1322 with: text += "and $his obedience grows.\n" replace line 1318 with: text += "and is very unhappy about it, although $his obedience grows.\n" replace line 1315 with: var text = "$name wears a pet suit " replace line 1312 with: return "$name is being stimulated by wearing a [color=yellow]Living suit[/color] and $his lust grows.\n" added partial support for items that add abilities(v4) add lines after 1280: #caution: abilities gained from items should not be acquirable by other means func abil(value): if value.ends_with('-'): value = toggleStrNeg(value) person.ability.erase(value) person.abilityactive.erase(value) else: if !person.ability.has(value): person.ability.append(value) if !person.abilityactive.has(value): person.abilityactive.append(value) fixed "Easterm Sword"(v3) replace line 1013 with: name = "Eastern Sword", variables.gd added description for chance of characters being constructed with a specialization(v3f) changed descriptions for meet and sex interaction time(v3b) changed list for constants mod by adding categories, corrected descriptions(i.e.,"modificator") (v4) added min and max to more entries(with decimals for conservative typing), added some overlooked and some newly qualifying variables (v4) replace lines 90-131 with: 'Character Creation & Stats' : { basehealth = {descript = "Character's health before modifiers", min = 1.0, max = 1000.0}, healthperend = {descript = "Bonus health per point of endurance", min = 0.0, max = 1000.0}, playerbonusstatpoint = {descript = "Bonus player stat points during char creation", min = 0.0, max = 1000.0}, basefoodconsumption = {descript = "Basic food consumption for characters per day", min = 0.0, max = 100.0}, skillpointsperlevel = {descript = "Attribute points gained on level-up", min = 0.0, max = 100.0}, learnpointsperstat = {descript = "Number of skill points required to increase mental stat by 1", min = 1.0, max = 100.0}, attributepointsperupgradepoint = {descript = "Number of attribute points required to increase upgrade points by 1", min = 1.0, max = 100.0}, specializationchance = {descript = "Percent chance of characters having a specialization", min = 0.0, max = 100.0}, banditishumanchance = {descript = "Percent chance of bandits being human", min = 0.0, max = 100.0}, playerstartbeauty = {descript = "Player's starting beauty stat", min = 0.0, max = 100.0}, characterstartbeauty = {descript = "Starting slave's starting beauty stat", min = 0.0, max = 100.0}, oldemily = {descript = "Use old Emily sprite"}, luxuryreqs = {descript = "Luxury required to satisfy slaves per grade", min = 0.0, max = 60.0}, }, 'Interactions' : { basesexactions = {descript = "Number of sex actions per day (before bonus from endurance)", min = 0.0, max = 1000.0}, basenonsexactions = {descript = "Number of non-sex actions per day (before bonus from endurance) ", min = 0.0, max = 1000.0}, timeforinteraction = {descript = "Number of actions you can perform during sex interaction sequence", min = 10.0, max = 1000.0}, timeformeetinteraction = {descript = "Number of actions you can perform during meet interaction sequence", min = 10.0, max = 1000.0}, }, 'Pregnancies' : { pregduration = {descript = "Basic pregnancy duration in days", min = 1.0, max = 1000.0}, growuptimechild = {descript = "Time required for baby to mature", min = 1.0, max = 1000.0}, growuptimeteen = {descript = "Time required for baby to mature", min = 1.0, max = 1000.0}, growuptimeadult = {descript = "Time required for baby to mature", min = 1.0, max = 1000.0}, traitinheritchance = {descript = "Chance to inherit a parent's trait", min = 0.0, max = 100.0}, babynewtraitchance = {descript = "Chance to gain a new trait", min = 0.0, max = 100.0}, }, 'Combat' : { damageperstr = {descript = "Raw damage per strength", min = 0.0, max = 100.0}, speedperagi = {descript = "Raw speed per agility", min = 0.0, max = 100.0}, speedbase = {descript = "Base speed for all characters", min = 0.0, max = 100.0}, baseattack = {descript = "Base attack for all characters", min = 0.0, max = 100.0}, }, 'Slave Price' : { priceperlevel = {descript = "Slave price modifier per level", min = 0.0, max = 1000.0}, priceperbasebeauty = {descript = "Slave price modifier per beauty", min = 0.0, max = 1000.0}, priceperbonusbeauty = {descript = "Slave price modifier per bonus beauty"}, pricebonusvirgin = {descript = "Slave price modifier for virgins", min = -10.0, max = 10.0}, pricebonusfuta = {descript = "Slave price modifier for futa", min = -10.0, max = 10.0}, pricebonusbadtrait = {descript = "Slave price modifier for bad traits", min = -10.0, max = 10.0}, pricebonustoxicity = {descript = "Slave price modifier for high toxicity", min = -10.0, max = 10.0}, priceuncivilized = {descript = "Slave price modifier for uncivilized trait", min = -10.0, max = 10.0}, priceminimum = {descript = "Minimum slave buy price", min = 0.0, max = 1000.0}, priceminimumsell = {descript = "Minimum slave sell price", min = 0.0, max = 1000.0}, gradepricemod = {descript = "Slave price modifier per grade", min = -10.0, max = 10.0}, agepricemods = {descript = "Slave price modifier per age", min = -10.0, max = 10.0}, }, 'Items & Backpack' : { geardropchance = {descript = "Percent chance of getting enemy's gear on defeat", min = 0.0, max = 100.0}, consumerope = {descript = "Number of ropes to be consumed when capturing a slave in the wild", min = 0.0, max = 5.0}, sellingitempricemod = {descript = "Selling price modifier for all items", min = 0.1, max = 1.0}, enchantitemprice = {descript = "Selling price modifier for enchanted gear", min = 1.0, max = 10.0}, basecarryweight = {descript = "Base carry weight", min = 0.0, max = 1000.0}, carryweightperstrplayer = {descript = "Bonus carry weight from player strength", min = 0.0, max = 1000.0}, baseslavecarryweight = {descript = "Bonus carry weight for having a slave in party", min = 0.0, max = 1000.0}, slavecarryweightperstr = {descript = "Bonus carry weight per slave's point of strength", min = 0.0, max = 1000.0}, }, added decimals to have consistant types inside dictionaries(v4) replace line 78 with: child = 0.0, teen = 0.0, adult = 0.0 replace line 74 with: "slave": -0.2, poor = 0.0, commoner = 0.2, rich = 0.5, noble = 1.0 added value for chance of characters being constructed with a specialization(v3f) add line after 13: var specializationchance = 5.0 added value for meet interaction time(v3b) add line after 10: var timeformeetinteraction = 10.0 removed unecessary warning suppression(v4) delete contents of line 2: #warning-ignore-all:unused_class_variable inventory.gd changed function used for loading item icons to support non-imported images(v3b) replace line 360 with: get_node("gearpanel/"+i).set_normal_texture(globals.loadimage(globals.state.unstackables[person.gear[i]].icon)) fixed choosing "Gear" or "Item" options in slave tab not highlighting the current slave replace line 312 with: if i.visible && i.has_meta('person') && i.get_meta('person') == person: changed function used for loading item icons to support non-imported images(v3b) replace line 271 with: button.get_node("icon").set_texture(globals.loadimage(i[0].icon)) improved efficiency of gear sort function, moved gear types array to file scope(v3c) replace lines 193-199 with: var valCmp = gearTypes.find(first[0].type) - gearTypes.find(second[0].type) if valCmp == 0: return first[0].name < second[0].name changed function used for loading item icons to support non-imported images(v3b) replace line 189 with: button.get_node("icon").set_texture(globals.loadimage(i[0].icon)) changed the inventory to show everything by default(v3d) add line after 86: selectcategory(get_node("everything")) changed function used for loading item icons to support non-imported images(v3b) replace line 54 with: get_node("iteminfo/TextureFrame").set_texture(globals.loadimage(item.icon)) moved gear types array to file scope(v3c) replace line 7 with: var gearTypes = ['weapon','armor','costume','underwear','accessory'] constructor.gd fixed game assigning non-image files as random portraits(v3d) replace line 182 with: var extensions = ["png","jpg","webp"] for i in globals.dir_contents(globals.setfolders.portraits): if !i.get_extension() in extensions: continue fixed persons being constructed with at most 100 health(v3d) replace line 79 with: person.health = 1000 slightly changed process for constructing characters with a specialization to substantially increase occurrence, moved chance to variables file(v3f) (specs besides housekeeper will still be very rare due to construction process) replace lines 68-72 with: if randf() < variables.specializationchance/100.0: globals.currentslave = person var possible = [] for i in globals.specarray: if globals.evaluate(globals.jobs.specs[i].reqs.replacen("person.consent == true","true").replacen("person.loyal >= 50","true")) == true: possible.append(i) if possible.size() > 0: person.spec = possible[randi()%possible.size()] if person.spec == 'bodyguard': person.add_effect(globals.effectdict.bodyguardeffect) races.gd fixed incorrect description of dryad racial bonus(v3e) replace line 218 with: details = "[color=aqua]Racial trait: forage is 40% more effective.[/color]\n\n[color=yellow]Stat potential: Strength - 3, Agility - 4, Magic - 5, Endurance - 4 [/color]", combatdata.gd fixed stuck exploration due to missing ambush description for goblins in mountain caves(v4) replace line 93 with: descriptionambush = "A [color=aqua]group of cave goblins[/color] jumps on you. ", aydashop.gd added gallery unlock upon first meeting Ayda in her shop(v4) add line after 23: globals.charactergallery.ayda.unlocked = true