diff --git a/README.md b/README.md index 17d2d28..d9a0816 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # botany - +![Screencap](http://tilde.town/~curiouser/botany.png) by Jake Funke - jifunks@gmail.com - tilde.town/~curiouser - http://jakefunke.online/ A command line, realtime, community plant buddy. @@ -11,7 +11,8 @@ Check in and water your plant every 24h to keep it growing. 5 days without water ## getting started botany is designed for unix-based systems. Clone into a local directory using `git clone https://github.com/jifunks/botany.git`. Run with `python botany.py`. Water your seed to get started. You can come and go as you please and your plant continues to grow. Make sure to come back and water every 24 hours or your plant won't grow. If your plant goes 5 days without water, it will die! - +*Note - botany.py must initially be run by the user who cloned/unzipped it +this initalizes the shared data file permissions.* ## features * Curses-based menu system * Persistent aging system that allows your plant to grow even when app is closed diff --git a/botany.py b/botany.py index de03ffc..68404d9 100644 --- a/botany.py +++ b/botany.py @@ -222,7 +222,7 @@ class Plant(object): # Create plant mutation # TODO: when out of debug this needs to be set to high number (1000 # even maybe) - CONST_MUTATION_RARITY = 1000 # Increase this # to make mutation rarer (chance 1 out of x) + CONST_MUTATION_RARITY = 2000 # Increase this # to make mutation rarer (chance 1 out of x) mutation_seed = random.randint(1,CONST_MUTATION_RARITY) if mutation_seed == CONST_MUTATION_RARITY: # mutation gained! @@ -307,6 +307,7 @@ class DataManager(object): savefile_name = this_user + '_plant.dat' savefile_path = os.path.join(botany_dir, savefile_name) garden_file_path = os.path.join(game_dir, 'garden_file.dat') + garden_json_path = os.path.join(game_dir, 'garden_file.json') def __init__(self): self.this_user = getpass.getuser() @@ -391,9 +392,6 @@ class DataManager(object): def garden_update(self, this_plant): # garden is a dict of dicts # garden contains one entry for each plant id - # TODO: this should calculate age based on time since start, not just - # when they saved it - # IE someone logged out, still gaining age, just not gaining ticks age_formatted = self.plant_age_convert(this_plant) this_plant_id = this_plant.plant_id plant_info = { @@ -409,16 +407,19 @@ class DataManager(object): with open(self.garden_file_path, 'rb') as f: this_garden = pickle.load(f) new_file_check = False - # TODO: it would be smart to lock this file down somehow, write to - # it only through the software (to prevent tampering) - # TODO: this is not the right way to do this, other users who run - # it can't chmod that file - # TODO: json file also needs to be writeable by all - # os.chmod(self.garden_file_path, 0666) else: - # create empty garden list + # create empty garden list and initalize file permissions this_garden = {} new_file_check = True + open(self.garden_file_path, 'a').close() + open(self.garden_json_path, 'a').close() + # If user has access, modify permissions to allow others to write + # This means the first run has to be by the file owner. + if os.stat(self.garden_file_path).st_uid == os.getuid(): + os.chmod(self.garden_file_path, 0666) + if os.stat(self.garden_json_path).st_uid == os.getuid(): + os.chmod(self.garden_json_path, 0666) + # if current plant ID isn't in garden list if this_plant.plant_id not in this_garden: this_garden[this_plant_id] = plant_info @@ -427,12 +428,12 @@ class DataManager(object): current_plant_ticks = this_garden[this_plant_id]["score"] if this_plant.ticks >= current_plant_ticks: this_garden[this_plant_id] = plant_info + + # dump garden file with open(self.garden_file_path, 'wb') as f: pickle.dump(this_garden, f, protocol=2) - - # create json file from plant_info - garden_json_path = os.path.join(self.game_dir,'garden_file.json') - with open(garden_json_path, 'w') as outfile: + # dump json file + with open(self.garden_json_path, 'w') as outfile: json.dump(this_garden, outfile) return new_file_check diff --git a/menu_screen.py b/menu_screen.py index 1760558..7922e56 100644 --- a/menu_screen.py +++ b/menu_screen.py @@ -71,7 +71,6 @@ class CursedMenu(object): self.screen.refresh() try: self.draw_default() - self.screen.border(0) self.screen.refresh() except Exception as exception: # Makes sure data is saved in event of a crash due to window resizing @@ -100,6 +99,7 @@ class CursedMenu(object): #traceback.print_exc() def ascii_render(self, filename, ypos, xpos): + # Prints ASCII art from file at given coordinates this_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)),"art") this_filename = os.path.join(this_dir,filename) this_file = open(this_filename,"r") @@ -111,7 +111,6 @@ class CursedMenu(object): def draw_default(self): # draws default menu - # TODO: draw bee clear_bar = " " * (int(self.maxx*2/3)) self.screen.addstr(2,2, self.title, curses.A_STANDOUT) # Title for this menu self.screen.addstr(4,2, self.subtitle, curses.A_BOLD) #Subtitle for this menu @@ -142,7 +141,9 @@ class CursedMenu(object): else: self.screen.addstr(5,13, clear_bar, curses.A_NORMAL) self.screen.addstr(5,13, " - you can't water a dead plant :(", curses.A_NORMAL) - self.ascii_render("bee.txt",-1,self.maxx-27) + + # This draws cute ascii from files + self.ascii_render("bee.txt",-1,self.maxx-23) def update_plant_live(self): # updates plant data on menu screen, live! @@ -193,13 +194,12 @@ class CursedMenu(object): this_plant = this_garden[plant_id] plant_table += this_plant["owner"] + " - " plant_table += this_plant["age"] + " - " - plant_table += str(this_plant["score"]) + " points - " + plant_table += str(this_plant["score"]) + "p - " plant_table += this_plant["description"] + "\n" return plant_table def draw_garden(self): # draws neighborhood - # TODO: use age from start date to now, not ticks or static clear_bar = " " * (self.maxx-2) + "\n" clear_block = clear_bar * 5 control_keys = [curses.KEY_UP, curses.KEY_DOWN, curses.KEY_LEFT, curses.KEY_RIGHT]