def save(self): """ Save this camera action to the cutscene. """ print("Saving") cameraSlide = Camera() cameraSlide.setPlace(self.locationO.currentText()) print("...") try: (int)(self.lx.text()) (int)(self.ly.text()) (int)(self.lz.text()) (int)(self.cx.text()) (int)(self.cy.text()) (int)(self.cz.text()) except ValueError: popup( "Camera position (x, y, z) and look direction (x, y, z) must be entered as whole numbers", "Critical") return cameraSlide.setLookAt(((int)(self.lx.text()), (int)(self.ly.text()), (int)(self.lz.text()))) cameraSlide.setCameraPosition( ((int)(self.cx.text()), (int)(self.cy.text()), (int)(self.cz.text()))) self.op.op.link.addItem(cameraSlide, self.op.op.i) print("Saved") self.op.op.linkstored.setLink(self.op.op.link, self.op.op.level, self.op.op.angle) self.op.op.linkstored.save() self.op.updateElementList() popup("Saved!", "Information")
def save(self): """ Save this movement action to the cutscene. """ print("Saving") moveSlide = Movement() moveSlide.setSubject(self.speaker.currentText()) moveSlide.setAnimation(self.ani.currentText()) print("...") try: (int)(self.lx.text()) (int)(self.ly.text()) except ValueError: popup("Destination coordinates (x, y) must be entered as integers", "Critical") return moveSlide.setDestination( ((int)(self.lx.text()), (int)(self.ly.text()))) self.op.op.link.addItem(moveSlide, self.op.op.i) print("Saved") self.op.op.linkstored.setLink(self.op.op.link, self.op.op.level, self.op.op.angle) self.op.op.linkstored.save() self.op.updateElementList() popup("Saved!", "Information")
def export(self): """ Export the story-creator data files to a user-selected locaion. """ fileBrowser = QFileDialog() fileBrowser.setFileMode(QFileDialog.Directory) fileBrowser.setViewMode(QFileDialog.Detail) fileBrowser.setOption(QFileDialog.ShowDirsOnly, True) if fileBrowser.exec_(): paths = fileBrowser.selectedFiles() else: print("Cancelled") return print("Copying data to " + str(paths[0]) + "/exportdata") try: copytree(json_reader.buildPath("data"), str(paths[0]) + "/exportdata") except OSError as e: print(e) popup( "Error in copying files. There is a file in the selected directory that has the same name " "as a Story Creator file.\n\nFiles are copied to " + str(paths[0]) + "/exportdata" + ". Please " "ensure this directory does not already exist.", "Critical") return print("Successfully copied files") popup("Files exported successfully!", "Information")
def viewF(self, graph): """ Toggle between the list and graph views of the social link. :param bool graph: whether the graph view should be displayed """ if graph: if len(self.link.getIDs()) == 0: popup("Nothing to show!", "Information") return self.graphicview = PrettySL(self.mainframe, self) self.listview.close() if self.cc: self.cc.close() self.view.setText("List View") self.grid.addWidget(self.graphicview, 0, 0, 1, 4) self.graphicview.show() self.view.clicked.disconnect() self.view.clicked.connect(lambda: self.viewF(False)) else: if self.cc: self.cc.show() else: self.listview = SLBase(self.mainframe, self) if self.graphicview: self.graphicview.close() self.view.setText("Graphic View") self.grid.addWidget(self.listview, 0, 0, 1, 4) self.listview.show() self.view.clicked.disconnect() self.view.clicked.connect(lambda: self.viewF(True)) self.mainframe.center()
def simulate(self): """ Simulate this cutscene. Pops open the simulation model, which is modal. """ if len(self.link.getIDs()) == 0: popup("Nothing to simulate!", "Information") return self.sim = Simulation(self.link, self.arcana, self.level, self.angle)
def importF(self): """ Import a file or set of files from disk into Story-Creator controlled directories. :raises AssertionError: with an object attempting to being loaded if the object cannot be loaded as a Social Link, Character or Persona. """ fileBrowser = QFileDialog() fileBrowser.setFileMode(QFileDialog.Directory) fileBrowser.setViewMode(QFileDialog.Detail) fileBrowser.setOption(QFileDialog.ShowDirsOnly, True) if fileBrowser.exec_(): paths = fileBrowser.selectedFiles() else: print("Cancelled") return print("Copying data from " + str(paths[0])) files = os.listdir(str(paths[0])) print(files) for file in files: if file.endswith(".json"): print("Copying valid file " + file) if "_link" in file: if self.checkOverwrite(file): copy(os.path.join(str(paths[0]), file), json_reader.buildPath("data")) else: try: # Ugly AF # TODO omgf this is more than ugly AF characterL = json_reader.readOne( file[:len(file) - 5], 'chars') assert "name" in characterL and "important" in characterL if self.checkOverwrite(file, 'chars'): copy(os.path.join(str(paths[0]), file), json_reader.buildPath("data/chars")) except AssertionError: print("Not a Character") try: personaL = json_reader.readOne( file[:len(file) - 5], 'pers') assert "name" in personaL and "arcana" in personaL if self.checkOverwrite(file, 'pers'): copy(os.path.join(str(paths[0]), file), json_reader.buildPath("data/pers")) except AssertionError: print("Not a Persona") raise AssertionError(personaL) print("Successfully copied files") popup("Files imported successfully!", "Information")
def save(self): """ Validate all info and save to file on disk. """ if os.path.exists(json_reader.buildPath("data/pers/"+self.nameT.text()+".json")): if not popup("Override existing Persona "+self.nameT.text()+"?", "Question"): return print("Saving") spellDeck = [] for combobox in self.iSpellOs: spellDeck.append(combobox.currentText()) stats = [self.strT.text(), self.magT.text(), self.endT.text(), self.agiT.text(), self.luckT.text()] res = [self.slashO.currentText(), self.strikeO.currentText(), self.pierceO.currentText(), self.fireO.currentText(), self.iceO.currentText(), self.elecO.currentText(), self.windO.currentText(), self.lightO.currentText(), self.darkO.currentText()] try: (int)(self.levelT.text()) (int)(self.strT.text()) (int)(self.magT.text()) (int)(self.endT.text()) (int)(self.agiT.text()) (int)(self.luckT.text()) except ValueError: popup("There is a number entry that isn't valid.\nEntries requiring numbers are:\nLEVEL\nSTR" "\nMAG\nEND\nAGI\nLUCK", "Critical") print("Not Saved") return if not (self.nameT.text() and not self.nameT.text().isspace()): popup("No name entered for your Persona. Name is a required field.", "Critical") print("No Name, not saved") return toWrite = Persona( self.nameT.text(), self.arcO.currentText(), self.levelT.text(), self.textT.toPlainText(), spellDeck, self.lsdic, stats, res, [self.listEL1.currentText(), self.listEL2.currentText()] ) json_reader.writeOne(toWrite, 'pers') temp = self.nameT.text() if (temp not in [self.listP.item(i).text() for i in range(self.listP.count())]): self.listP.addItem(temp) self.loadPer(temp) print("Saved Persona")
def deleteangle(self): """ Completely delete a certain level/angle combo. This will remove all info, the cutscene, etc. Dangerous. """ if not popup( "WARNING!!!\n\nThis will COMPLETELY ERASE this cutscene. It is HIGHLY RECOMMENDED that " "you back up your data by going to the Support/Contact page and choose \"Export\".", "Warning"): return link = SocialLink(self.arcSel.currentText()) print(link.cutscenes) key = self.levelOM.currentText()[self.levelOM.currentText().index(" ")+1:] + \ "_" + \ self.angleOM.currentText()[self.angleOM.currentText().index(" ")+1:] print(key) if key in link.cutscenes: link.cutscenes.pop(key) link.save() self.angleOM.removeItem(self.angleOM.currentIndex()) if self.angleOM.count() == 0: self.angleOM.addItem("No angles") self.delang.close() print(link.cutscenes) print("Deleted")
def save(self): """ Save this action into the cutscene. """ print("Saving") infoSlide = Info() print("...") infoSlide.setText(self.infoBox.toPlainText()) print(self.op.op.i) self.op.op.link.addItem(infoSlide, self.op.op.i) print("Saved") self.op.op.linkstored.setLink(self.op.op.link, self.op.op.level, self.op.op.angle) self.op.op.linkstored.save() self.op.updateElementList() popup("Saved!", "Information")
def addAngle(self): """ Add a potential angle to this link/level. """ try: (int)(self.newAng.text()) if self.angs[0] == "No angles": self.angleOM.clear() self.delang = QPushButton(self, text="Delete Angle") self.delang.clicked.connect(self.deleteangle) self.grid.addWidget(self.delang, 4, 2, 1, 2) self.angleOM.addItem("Angle " + str(self.newAng.text())) self.angleOM.setCurrentIndex(self.angleOM.count() - 1) self.newAng.clear() except ValueError: popup("The Angle must be an integer", "Critical")
def addLS(self): """ Add a learned spell to the list, based on what was entered. """ print("Adding learned spell") chosenSpell = self.lsSpellO.currentText() if (int)(self.lslevel.text()) <= (int)(self.levelT.text()): popup("You cannot add a spell at an earlier level than the Persona's base level", "Critical") return if chosenSpell != "": print("Ok") self.lsdic[chosenSpell] = self.lslevel.text() self.listLS.addItem(chosenSpell + " at level " + self.lslevel.text()) self.lslevel.setText("") self.lsSpellO.setCurrentIndex(0) return popup("You must choose a spell", "Critical")
def saveinfo(self): """ Set the info in the social link object and save it. """ try: for angle, data in self.reqs.textboxes.items(): (int)(data.text()) if data.text() != "": if self.level.currentText( ) not in self.link.requiredPoints: self.link.requiredPoints[self.level.currentText()] = {} if angle not in self.link.requiredPoints[ self.level.currentText()]: self.link.requiredPoints[ self.level.currentText()][angle] = {} self.link.requiredPoints[ self.level.currentText()][angle]['points'] = int( data.text()) for angle, data in self.reqs.courages.items(): self.link.requiredPoints[ self.level.currentText()][angle]['courage'] = int( data.currentText()) for angle, data in self.reqs.charms.items(): self.link.requiredPoints[ self.level.currentText()][angle]['charm'] = int( data.currentText()) for angle, data in self.reqs.acads.items(): self.link.requiredPoints[ self.level.currentText()][angle]['acad'] = int( data.currentText()) for angle, data in self.reqs.ultis.items(): self.link.finalpersona[angle] = data.currentText() self.link.pseudoname = self.pseudoname.text() self.link.info = self.aitext.toPlainText() if self.linklevel: if str(self.linklevel) + "_" + str( self.linkangle) not in self.link.cutinfo: self.link.cutinfo[str(self.linklevel) + "_" + str(self.linkangle)] = "" self.link.cutinfo[str(self.linklevel) + "_" + str( self.linkangle)] = self.titext.toPlainText() except ValueError: popup("Points must be integers.\nNot saved.", "Critical") return self.link.save() popup("Saved", "Information")
def begin(self): """ Enter the social link cutscene editor. """ if self.angleOM.currentText() == "No angles": popup( "An Angle must be selected.\nCreate angles by entering a number in the text box below and " "clicking \"Add Angle\"", "Critical") return enter_level = str(self.levelOM.currentText() )[str(self.levelOM.currentText()).index(" ") + 1:] enter_angle = str(self.angleOM.currentText() )[str(self.angleOM.currentText()).index(" ") + 1:] print("Entered SL creation mode for arcana " + str(self.arcSel.currentText())) self.mainframe.changeState( SLFrame(self.mainframe, self, str(self.arcSel.currentText()), int(enter_level), int(enter_angle)))
def back(self): """ Return to the higher-level cutscene container view... """ if not popup("Return to list main menu?\n(Lose any unsaved changes)", "Warning"): return self.close() self.op.cc = None self.op.viewF(False)
def send(self): """ Send entered text as email to me via SMTP. """ if str(self.body.toPlainText()) == "" or \ str(self.body.toPlainText()).isspace() or \ str(self.subject.text()) == "" or \ str(self.subject.text()).isspace(): popup("Please enter a message and subject.", "Critical") return msg = MIMEMultipart() body = MIMEText( str(self.body.toPlainText() + "\n\nSent by " + self.semT.text())) msg.attach(body) msg['From'] = str(self.semT.text()) msg['To'] = "*****@*****.**" msg['Subject'] = str(self.subject.text()) if self.addFiles.isChecked(): print("Adding files") fileNames = glob(json_reader.buildPath("data/*.json")) + \ glob(json_reader.buildPath("data/pers/*.json")) + \ glob(json_reader.buildPath("data/chars/*.json")) print(fileNames) for file in fileNames: part = MIMEBase('application', "octet-stream") part.set_payload(open(file, "rb").read()) part.add_header( 'Content-Disposition', 'attachment; filename="%s"' % file[file.rfind("/"):]) msg.attach(part) serv = smtplib.SMTP("smtp.live.com", 587) serv.set_debuglevel(1) serv.ehlo() serv.starttls() serv.ehlo() serv.login("*****@*****.**", 'PersonaX') try: serv.sendmail(msg['From'], msg['To'], msg.as_string()) print("Message sent successfully") popup("Email was sent! Thank you!", "Information") serv.quit() return except smtplib.SMTPSenderRefused: popup( "You must provide your email address so that we may contact you if needed.\n\nYour email " "address will not be shared with any third parties.", "Critical") serv.quit() return except Exception as e: #pylint: disable=broad-except print(e) popup("Email failed to send, but not sure why...", "Critical")
def lightConnect(self): """ Create a relationship between the current action and another. """ if not self.checkCached(): popup("Please save this action before linking it to a new one", "Information") return if self.next.currentText() == "New element": self.op.link.addRelation(self.op.i, self.op.link.size()) print("Linked to index " + str(self.op.link.size())) self.op.i = self.op.link.size() self.load = 0 self.changeFrame(0) self.updateElementList() else: self.op.link.addRelation( self.op.i, self.actions.index(self.next.currentText())) print("Linked to index " + str(self.actions.index(self.next.currentText()))) self.populateExistingConnections()
def remove(self): """ Remove a character from the list, and remove them from disk. """ if not popup("Are you certain you want to completely remove this character?\n(Cannot be undone)", "Warning"): return print("Removing character " + self.allChars.currentText()) json_reader.deleteChar(self.allChars.currentText()) self.allChars.removeItem(self.allChars.currentIndex()) self.allChars.setCurrentIndex(self.allChars.count()-1) self.loadChar("New")
def save(self): """ Save a character to disk from the information entered in the GUI. """ if self.nameT.text() in ["New", ""]: popup("Sorry, your character cannot be called \""+self.nameT.text()+"\". That is a reserved " "keyword (and it's also a dumb name)", "Critical") return print("Saving") try: toWrite = Character(self.nameT.text(), self.infoT.toPlainText(), self.importantB.isChecked()) except UnicodeEncodeError as e: print(e) print(type(e)) popup("Sorry, unicode characters are not supported.", "Critical") return json_reader.writeOne(toWrite, 'chars') if toWrite.getName() not in [self.allChars.itemText(i) for i in range(self.allChars.count())]: self.allChars.insertItem(self.allChars.count()-1, self.nameT.text()) self.allChars.setCurrentIndex(self.allChars.count()-2) print("Saved")
def new(self): """ Open an empty Persona edit view. """ if self.createFrame and not popup("Override any unsaved changes?", "Warning"): return if self.createFrame: self.createFrame.close() self.buttonFrame.close() self.initUI(False) self.createFrame.show() self.mainframe.center() print("Created")
def remove(self): """ Remove a created Persona from the list and delete the file on disk. """ if self.listP.currentItem().text() == "": return if not popup( "Are you certain you want to completely remove this Persona?\n(Cannot be undone)", "Warning" ): return print("Removing Persona " + self.listP.currentItem().text()) json_reader.deletePer(self.listP.currentItem().text()) self.listP.takeItem( [self.listP.item(i).text() for i in range(self.listP.count())].index( self.listP.currentItem().text()) )
def checkOverwrite(self, filepath, ctype=''): """ Confirm with user if file should be overwritten. :param str filepath: path to file that could be overwritten :param str ctype: chars or pers if the file represents either type """ if ctype: ctype = ctype + "/" if os.path.exists(os.path.join(json_reader.buildPath("data"), filepath)): if popup( "File " + filepath[:len(filepath) - 5] + " already exists. Overwrite?", "Warning"): os.remove( json_reader.buildPath("data/%s%s" % (ctype, filepath)))
def removeRelation(self): """ Remove a relation, which will also delete the uniquely dependant subtree. """ if not self.existing_connections.currentItem() or \ not popup("Are you sure you want to remove this relation? Any elements with a unique dependancy " "on this relation will also be deleted.\nIt is highly recommended you take a look at " "the graphical view of the tree in order to see the potential effects of the deletion.", "Warning"): return self.op.link.delRelation( self.op.i, self.actions.index(self.existing_connections.currentItem().text())) self.populateExistingConnections() self.updateElementList() self.op.linkstored.save()
def edit(self): """ Switch to edit view, also loads the selected Persona. """ try: if self.listP.currentItem().text() != "": if self.createFrame and not popup("Override any unsaved changes?", "Warning"): return self.loadPer(self.listP.currentItem().text()) except AttributeError: # To initialize createFrame UI before load if self.listP.currentItem().text() != "": temp = self.listP.currentItem().text() self.buttonFrame.close() self.initUI(False) self.loadPer(temp) else: return self.createFrame.show() self.mainframe.center() print("Changed to edit frame")
def deleteSubtree(self): """ Delete the subtree of the current selected index. """ if not popup( "Are you certain you want to delete this item and it's subtree?\n(Everything in red and" " yellow will be deleted)", "Warning"): return self.graph.delItem(self.lastButtonPressed) self.lab.close() self.initData() self.lastButtonPressed = None self.delete.close() self.delete = None self.subtree = [] self.needsRefresh = True self.idLabel.close() self.edit.clicked.disconnect() self.edit.close() self.op.linkstored.save() self.tree.close() self.tree = TreeWidget(self, self.actionObjs, self.actionIDs, self.table) self.grid.addWidget(self.tree, 0, 0, 10, 3)
def save(self): """ Save this speak action to the cutscene. """ print("Saving") print("...") speakSlide = Speak() speakSlide.setText(self.infoBox.toPlainText()) speakSlide.setSpeaker(self.speaker.currentText()) speakSlide.emotion = self.emotion.currentText() for i in range(len(self.pointvec)): if self.pointvar[i].currentText() != "": try: amount = (int)(self.pointvec[i].text()) speakSlide.putPoints(self.pointvar[i].currentText(), amount) except ValueError: popup( "All Points must be integers.\nTo discard one line, empty the text field and set " "the arcana to blank.", "Critical") print("Amount must be an integer") for i in range(len(self.anglevec)): if self.anglevar[i].currentText() != "": try: amount = (int)(self.anglevec[i].text()) speakSlide.putAngle(self.anglevar[i].currentText(), amount) except ValueError: popup( "All Points and Angles must be integers.\nTo discard one line, set empty the text " "field and set the arcana to blank.", "Critical") print("Amount must be an integer") self.op.op.link.addItem(speakSlide, self.op.op.i) print("Saved") self.op.op.linkstored.setLink(self.op.op.link, self.op.op.level, self.op.op.angle) self.op.op.linkstored.save() self.op.updateElementList() popup("Saved!", "Information")