Skip to content

Instantly share code, notes, and snippets.

@jh0ker
Last active January 6, 2024 14:35
Show Gist options
  • Star 16 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save jh0ker/1b8dd16f113b7ddc7b90e617ac0851c4 to your computer and use it in GitHub Desktop.
Save jh0ker/1b8dd16f113b7ddc7b90e617ac0851c4 to your computer and use it in GitHub Desktop.
Max attributes and skills in SCUM game single player

README

This script manipulates the SCUM database for the single player mode to increase the level of all skills and attributes to max (or the value of your choice) for a given prisoner. This script does not work for multiplayer characters.

You can edit the configuration settings SET_ATTRIBUTES and SET_SKILLS at the start of the script below to change the target values for the skills and attributes. Default is maxed out.

Tested with SCUM Build 0.9.101.72873

How do I use it?

You need to have Python installed on your computer. The script was tested with Python 3.11 - older versions may work, newer versions should be fine.

Download Python from python.org and install it. I recommend you tick the option "Add to PATH" during the install if there is one.

Now, download the max_prisoner.py script file by right-clicking on the Raw button in its title bar and selecting "Save link as...". Save it somewhere you can easily find it.

Make sure you are not currently in a single player game (being in the main menu should be fine). Now, you should be able to run the script by simply double-clicking it in Windows. If this does not work, right click the file and select "Open with" -> "Python".

The script will automatically create a backup of your current DB and ask you which prisoner/character to work on. If everything works out correctly, it will look something like this:

image

Inspired by https://gist.github.com/quonic/279da005187df6e611b1b31859d91eeb

"""
This script manipulates the SCUM database for the single player mode to
increase the level of all skills and attributes to max (or the value of
your choice).
Edit the constants below to change the target values for the skills and
attributes. Default is maxed out.
Tested with Python 3.11 on August 5th, 2023 with SCUM Build 0.9.101.72873
"""
from dataclasses import dataclass
import datetime as dt
import os
from pathlib import Path
import shutil
import sqlite3
import struct
import traceback
from typing import Literal
#### Configuration ####
## Main attributes ##
SET_ATTRIBUTES = {
"BaseStrength": 8.0, # 1.0 to 8.0
"BaseConstitution": 5.0, # 1.0 to 5.0
"BaseDexterity": 5.0, # 1.0 to 5.0
"BaseIntelligence": 5.0, # 1.0 to 5.0
}
## Skills ##
"""
You can remove skills from the list below and they will not be changed.
If a new skill is added to the game, you can add it to the list below.
The first number in each line is the skill level (0 - 3)
The second number is the skill experience (0 - 10000000)
"""
SET_SKILLS = {
"BoxingSkill": (3, 10000000),
"AwarenessSkill": (3, 10000000),
"RiflesSkill": (3, 10000000),
"SnipingSkill": (3, 10000000),
"CamouflageSkill": (3, 10000000),
"SurvivalSkill": (3, 10000000),
"MeleeWeaponsSkill": (3, 10000000),
"HandgunSkill": (3, 10000000),
"RunningSkill": (3, 10000000),
"EnduranceSkill": (3, 10000000),
"TacticsSkill": (3, 10000000),
"CookingSkill": (3, 10000000),
"ThieverySkill": (3, 10000000),
"ArcherySkill": (3, 10000000),
"DrivingSkill": (3, 10000000),
"EngineeringSkill": (3, 10000000),
"DemolitionSkill": (3, 10000000),
"MedicalSkill": (3, 10000000),
"MotorcycleSkill": (3, 10000000),
"StealthSkill": (3, 10000000),
"AviationSkill": (3, 10000000),
"ResistanceSkill": (3, 10000000),
"FarmingSkill": (3, 10000000),
}
# Other constants
USER = os.getlogin()
DB_PATH = Path(f"C:/Users/{USER}/AppData/Local/SCUM/Saved/SaveFiles/SCUM.db")
BODY_SIM_KEY_PADDING = 5
BODY_SIM_VALUE_PADDING = 10
@dataclass
class PropertyType:
"""Just a small class to define property types as they occur in the body simulation blob."""
name: bytes
width: int # in bytes
# Used for converting with Python types
struct_type: Literal["<d", "<f", "<?"]
DoubleProperty = PropertyType(name=b"DoubleProperty", width=8, struct_type="<d")
FloatProperty = PropertyType(name=b"FloatProperty", width=4, struct_type="<f")
BoolProperty = PropertyType(name=b"BoolProperty", width=1, struct_type="<?")
def load_prisoner(con: sqlite3.Connection, id: int):
"""Load prisoner from database."""
cur = con.execute("SELECT * FROM prisoner WHERE id = ?", (id,))
result = {desc[0]: val for desc, val in zip(cur.description, cur.fetchone())}
return result
def save_prisoner(con: sqlite3.Connection, prisoner: dict):
"""Updates prisoner in database. Currently only sets body_simulation."""
return con.execute(
"UPDATE prisoner SET body_simulation = ? WHERE id = ?",
(prisoner["body_simulation"], prisoner["id"]),
)
def update_body_sim(body_sim: bytearray, key: bytes, value: float, property_type: PropertyType):
# Find the key in the body simulation blob
key_offset = body_sim.index(key)
# Make sure we are using the correct property type
assert (
body_sim[
key_offset
+ len(key)
+ BODY_SIM_KEY_PADDING : key_offset
+ len(key)
+ BODY_SIM_KEY_PADDING
+ len(property_type.name)
]
== property_type.name
)
# Calculate offset of actual value
value_offset = (
key_offset
+ len(key)
+ BODY_SIM_KEY_PADDING
+ len(property_type.name)
+ BODY_SIM_VALUE_PADDING
)
# Convert value to bytes
value_bytes = struct.pack(property_type.struct_type, value)
# Update value in body sim blob
body_sim[value_offset : value_offset + property_type.width] = value_bytes
def update_skills(con: sqlite3.Connection, prisoner: dict):
"""Sets all skills to max level in the database."""
for (name,) in con.execute(
"SELECT name FROM prisoner_skill WHERE prisoner_id = ?", (prisoner["id"],)
):
if name not in SET_SKILLS:
continue
new_level, new_experience = SET_SKILLS[name]
# Finally, update the XML and other fields in the database
con.execute(
"UPDATE prisoner_skill SET level = ?, experience = ? WHERE prisoner_id = ? AND name = ?",
(new_level, new_experience, prisoner["id"], name),
)
def choose_prisoner(con: sqlite3.Connection):
"""Choose prisoner to update."""
cur = con.execute(
"SELECT prisoner.id, user_profile.name FROM prisoner LEFT JOIN user_profile ON prisoner.user_profile_id = user_profile.id WHERE user_profile.authority_name is ?",
(None,),
)
print("\nFound prisoners in local single player:\n")
for id, name in cur:
print(f'"{name}" with ID {id}')
return int(input("\nEnter prisoner ID: "))
def main():
print("Backing up database... ")
filename_safe_iso = dt.datetime.now().isoformat().replace(":", "-")
backup_path = DB_PATH.with_name(f"SCUM-bak-{filename_safe_iso}.db")
shutil.copy(DB_PATH, backup_path)
print(f"Backed up to: {backup_path}")
print("\nConnecting to database...")
con = sqlite3.connect(DB_PATH)
# Choose prisoner interactively
prisoner_id = choose_prisoner(con)
print(f"Loading prisoner with ID {prisoner_id}...")
prisoner = load_prisoner(con, prisoner_id)
print("\nUpdating attributes... ", end="")
body_sim = bytearray(prisoner["body_simulation"])
for attribute, value in SET_ATTRIBUTES.items():
update_body_sim(
body_sim,
attribute.encode("ascii"),
value,
DoubleProperty,
)
prisoner["body_simulation"] = bytes(body_sim)
save_prisoner(con, prisoner)
print("Success!")
print("Updating skills... ", end="")
update_skills(con, prisoner)
print("Success!")
con.commit()
input("\nAll done! Press enter to exit.")
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
print("\nExiting...")
except Exception:
print("\n\nSomething went wrong...\n\n")
traceback.print_exc()
input("\n\nPress enter to exit.")
"""
This script manipulates the SCUM database for the single player mode to
repair placed items by the chosen player.
Tested with Python 3.10 on September 15, 2022 with SCUM Build 0.7.162.51364
"""
import datetime as dt
import os
import shutil
import sqlite3
import traceback
import xml.etree.ElementTree as ET
from pathlib import Path
from typing import Tuple
#### Configuration ####
# No configuration :)
# Other constants
USER = os.getlogin()
DB_PATH = Path(f"C:/Users/{USER}/AppData/Local/SCUM/Saved/SaveFiles/SCUM.db")
def repair_base_element(con: sqlite3.Connection, prisoner_id: int):
"""Reset health of base elements like walls, foundations and some other stuff."""
con.execute(
"UPDATE base_element SET element_health = ? WHERE creator_prisoner_id = ?",
(1.0, prisoner_id),
)
def repair_virtualized_item(con: sqlite3.Connection, user_profile_id: int):
"""Reset health of other buildings and dropped items."""
for item_id, xml in con.execute(
"SELECT id, item_xml FROM virtualized_item WHERE user_profile_id = ?",
(user_profile_id,),
):
# Parse XML, modify health and max health, and convert back to XML
string_terminator = "\x0a\x00"
root = ET.fromstring(xml.rstrip(string_terminator))
root.set("_health", "1")
root.set("_maxHealth", "1")
new_xml = ET.tostring(root, encoding="unicode") + string_terminator
# Finally, update the XML and other fields in the database
con.execute(
"UPDATE virtualized_item SET item_xml = ? WHERE id = ?",
(new_xml, item_id),
)
def choose_prisoner(con: sqlite3.Connection) -> Tuple[int, int]:
"""Choose prisoner to update. Returns a tuple (prisoner_id, user_profile_id)."""
cur = con.execute(
"SELECT prisoner.id, user_profile.name, user_profile.id FROM prisoner LEFT JOIN user_profile ON prisoner.user_profile_id = user_profile.id WHERE user_profile.authority_name is ?",
(None,),
)
prisoners = {
prisoner_id: {"name": name, "user_profile_id": user_profile_id}
for (prisoner_id, name, user_profile_id) in cur
}
print("\nFound prisoners in local single player:\n")
for prisoner_id, data in prisoners.items():
print(f'"{data["name"]}" with ID {prisoner_id}')
chosen_prisoner_id = int(input("\nEnter prisoner ID: "))
if chosen_prisoner_id not in prisoners:
raise ValueError(f"Prisoner ID {chosen_prisoner_id} not found!")
return (chosen_prisoner_id, prisoners[chosen_prisoner_id]["user_profile_id"])
def main():
print("Backing up database... ")
filename_safe_iso = dt.datetime.now().isoformat().replace(":", "-")
backup_path = DB_PATH.with_name(f"SCUM-bak-{filename_safe_iso}.db")
shutil.copy(DB_PATH, backup_path)
print(f"Backed up to: {backup_path}")
print("\nConnecting to database...")
con = sqlite3.connect(DB_PATH)
# Choose prisoner interactively
prisoner_id, user_profile_id = choose_prisoner(con)
print('Repairing items in table "base_element"... ', end="")
repair_base_element(con, prisoner_id)
print("Success!")
print('Repairing items in table "virtualized_item"... ', end="")
repair_virtualized_item(con, user_profile_id)
print("Success!")
con.commit()
input("\nAll done! Press enter to exit.")
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
print("\nExiting...")
except Exception:
print("\n\nSomething went wrong...\n\n")
traceback.print_exc()
input("\n\nPress enter to exit.")
@jh0ker
Copy link
Author

jh0ker commented Dec 22, 2022

@FoxMulder13 Glad to hear it!

@B00BLASTER
Copy link

If I own a scum server is it possible to use this somehow to increase my characters attributes like your prisoner script?

@B00BLASTER
Copy link

If I own a scum server is it possible to use this somehow to increase my characters attributes like your prisoner script?

My Server is on GPortal and my discord is boo#6363 if you could find something please send here or reply in comments thanks love your work!

@jimmy-mook
Copy link

Is it working on the newest update?

@foodstampz313
Copy link

does not seem to be working it makes the DB back up but nothing after that

@jh0ker
Copy link
Author

jh0ker commented May 5, 2023

@foodstampz313 @jimmy-mook I just tested it, on my end it's still working correctly.

@foodstampz313 Can perhaps give some more information, like the exact output of the script?

If it gets stuck after entering the prisoner ID, that is something I've seen before. It seems to be a problem with reading the user input. If that is the case for you, try downloading this script and replace the number 123 in line 27 that says PRISONER_ID = 123 with the actual prisoner ID. That version of the script will skip the interactive ID selection process.

@andreas12793
Copy link

andreas12793 commented May 11, 2023

Dear jh0ker

there seems to be an issue with the latest update ( 8.5)
this is the error im getting.

========

Enter prisoner ID: 10
Loading prisoner with ID 10...

Updating attributes... Success!
Updating skills...

Something went wrong...

Traceback (most recent call last):
File "C:\Users\IcedCaramelCream\Desktop\PROGRAMS\SCUM stats edit\max_prisoner.py", line 222, in
main()
File "C:\Users\IcedCaramelCream\Desktop\PROGRAMS\SCUM stats edit\max_prisoner.py", line 213, in main
update_skills(con, prisoner)
File "C:\Users\IcedCaramelCream\Desktop\PROGRAMS\SCUM stats edit\max_prisoner.py", line 155, in update_skills
root = ET.fromstring(xml.rstrip(string_terminator))
AttributeError: 'NoneType' object has no attribute 'rstrip'

@jimmy-mook
Copy link

@jh0ker @foodstampz313 It worked for me when I had downloaded it. My bad for taking so long, I had forgot my pw for this thing. It doesnt work on the newest update obviously. It was really cool while it lasted. Hopefully it gets updated for the newest version.

@jh0ker
Copy link
Author

jh0ker commented May 12, 2023

@andreas12793 @jimmy-mook Thanks for your feedback. I published an updated version of the script, tested and working with SCUM version 0.8.500.67830 (HELL'S KITCHEN update). The required change was relatively minor, in fact the database model for the skills has been simplified.

There is a new BLOB field that seems to be exclusively used by the cooking skill, so if you notice anything weird with cooking specifically, please let me know (although it is a new feature so some bugs are expected). I'm not touching that field, so I don't expect any issues. Even deleting it seemed to have no negative effect, the game restored it on its own. However, if you want to be 100% safe, you can remove the CookingSkill line 54 from the script.

@jimmy-mook
Copy link

jimmy-mook commented May 13, 2023

@foodstampz313 Been having some trouble running the script through python. I tried opening it with python but would keep getting a window telling me to update python. After I did it still won't open it successfully.

@jimmy-mook
Copy link

Dude I'm so dumb I was downloading the read me script instead of the max prisoner one smh lol

@jimmy-mook
Copy link

It works like a charm brother! Great work again.

@andreas12793
Copy link

Appreciated it ! Thank you!

@liamrose98
Copy link

Hi @jh0ker, how will I be able to do this on a online server that I own personally? I have experimented with the Doublefloat 64 and changed the attributes, it appears to work on my character in the main menu screen it shows him bigger than what i created him. But when I load into my online server it doesn't show any changes physically or written in the attributes.

@jh0ker
Copy link
Author

jh0ker commented Jun 1, 2023

@liamrose98 I'm not sure what you've been doing, but it is my understanding that there is currently no server host that allows you to access the server database directly, which would be needed for this script to work.

@GBonesJones
Copy link

Hi sir, are there any way to do it in Online server? I'm gonna be honest, I'm too tired of grinding those skills and I have a hard time playing solo without medical, thievery, etc. Please help me if you could.

@Ktulu19
Copy link

Ktulu19 commented Nov 13, 2023

Hi im having some isssies to setting the skills and attributes. I type SET_SKILLS and the other one and it gives me this error. if you could help it would be awesome

Backing up database...
Backed up to: C:\Users\Owner\AppData\Local\SCUM\Saved\SaveFiles\SCUM-bak-2023-11-13T18-26-08.557219.db

Connecting to database...

Found prisoners in local single player:

"Jakuza" with ID 3

Enter prisoner ID: SET_ATTRIBUTES

Something went wrong...

Traceback (most recent call last):
File "D:\Users\Owner\Desktop\max_prisoner.py", line 211, in
main()
File "D:\Users\Owner\Desktop\max_prisoner.py", line 180, in main
prisoner_id = choose_prisoner(con)
^^^^^^^^^^^^^^^^^^^^
File "D:\Users\Owner\Desktop\max_prisoner.py", line 166, in choose_prisoner
return int(input("\nEnter prisoner ID: "))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ValueError: invalid literal for int() with base 10: 'SET_ATTRIBUTES'

@jh0ker
Copy link
Author

jh0ker commented Nov 14, 2023

Hey @Ktulu19

I'm a little confused why you would type "SET_SKILLS" into the prompt for the prisoner ID, in your case you should probably just type "3" since that is the one prisoner you have. See the screenshot for how it should look.

If you want to modify exactly which level your skills/attributes should be changed to, you will have to modify the script itself. Don't worry, it's not very difficult. The values you need to change are towards the beginning of the script. Simply open it with a text editor of your choice and look for the variables SET_ATTRIBUTES and SET_SKILLS.

@Bazerkr
Copy link

Bazerkr commented Nov 25, 2023

hello @jh0ker
i was wondering how a lowly plebeian such as myself with absolutely no idea how to use python might change the strength stat to 5? for um ... scientific reasons ? i don't really have a reason other than aesthetics.

@jh0ker
Copy link
Author

jh0ker commented Nov 25, 2023

Hey @Bazerkr
Assuming you only want to change your Strength attribute and not make any other changes to your character, you want your configuration section (lines 23-66 in the original script) to look like this:

#### Configuration ####

## Main attributes ##
SET_ATTRIBUTES = {
    "BaseStrength": 5.0,  # 1.0 to 8.0
}

## Skills ##
SET_SKILLS = {
}

Simply open the script in any text editor you want, even notepad will work just fine. Simply replace the entire configuration section (lines 23-66) fully with the snippet above. Save the file and run it like normal, no extra steps needed.

By the way, in case you are unaware, the Strength stat goes up to 8, unlike the other stats.

@Bazerkr
Copy link

Bazerkr commented Nov 26, 2023

thank you @jh0ker
i have done the steps above and used notepad to do it but it dose not allow me to open it the same way the raw file you originally provided does im not sure if im missing something or if im just that computer illiterate haha

Edit: i figured it out your the best thank you !!

@jh0ker
Copy link
Author

jh0ker commented Nov 26, 2023

@Bazerkr glad to hear it!

@bakedbeangaming
Copy link

@jh0ker Hi, after checking this out today looks like it's not working after SCUM - Hotfix 0.9.511.80646

@jh0ker
Copy link
Author

jh0ker commented Dec 21, 2023

@bakedbeangaming Hey, I just tried it with both an old character and a fresh one and it seemed to work fine for me in both cases. Did you get any kind of error message that you could share with me? Also, did you use it successfully in the past, or is this your first time trying it?

@bakedbeangaming
Copy link

@jh0ker Hi, thanks for taking the time to get back to me no I got no error message was as if it had been done but upon checking stats nothing had changed iv just gone and tried it again with new and old but still nothing changed for me

@jh0ker
Copy link
Author

jh0ker commented Dec 22, 2023

@bakedbeangaming Hmm... if it did run successfully, that's strange. Have you tried shutting off your game completely before running the script? Maybe the changes got overwritten by something in the game. Did you make any modifications to the script? If yes, try re-downloading the original. If it still doesn't work, maybe you could send me your save game and I'll take a look if there's anything different with that. You can send it to me on Discord if you want, my username there is the same as here, jh0ker

@bakedbeangaming
Copy link

thank you ill have a go at it again and will pm you in discord

@bakedbeangaming
Copy link

@bakedbeangaming Hmm... if it did run successfully, that's strange. Have you tried shutting off your game completely before running the script? Maybe the changes got overwritten by something in the game. Did you make any modifications to the script? If yes, try re-downloading the original. If it still doesn't work, maybe you could send me your save game and I'll take a look if there's anything different with that. You can send it to me on Discord if you want, my username there is the same as here, jh0ker

hi iv sent you a friend request on discord as it would not let me inbox you or send save file

@jh0ker
Copy link
Author

jh0ker commented Dec 23, 2023

Hey @bakedbeangaming I don't see any friend requests on my end, not sure why

@bakedbeangaming
Copy link

@jh0ker just like to say a big thank you to jh0ker for all your time in helping me much love and again thank you all sorted

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment