diff options
author | Jesusaves <cpntb1@ymail.com> | 2020-12-18 00:47:22 -0300 |
---|---|---|
committer | Jesusaves <cpntb1@ymail.com> | 2020-12-18 00:47:22 -0300 |
commit | a42807c6c632615500a08c77e06d16ae346e46b1 (patch) | |
tree | 681d3f8b7fac9da32410b567459f9d6d354389ae /player.py | |
parent | b1c8aa49ad2e5e310c93177b0656ede46c87cb84 (diff) | |
download | server-a42807c6c632615500a08c77e06d16ae346e46b1.tar.gz server-a42807c6c632615500a08c77e06d16ae346e46b1.tar.bz2 server-a42807c6c632615500a08c77e06d16ae346e46b1.tar.xz server-a42807c6c632615500a08c77e06d16ae346e46b1.zip |
Registrations should be working again.
Bump client version so it is now authorized! \o/
Diffstat (limited to 'player.py')
-rw-r--r-- | player.py | 833 |
1 files changed, 833 insertions, 0 deletions
diff --git a/player.py b/player.py new file mode 100644 index 0000000..30172a6 --- /dev/null +++ b/player.py @@ -0,0 +1,833 @@ +######################################################################################## +# This file is part of Spheres. +# Copyright (C) 2019 Jesusalva + +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. + +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. + +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +######################################################################################## +# Player Module (parties, inventory, and player data) + +from utils import * +from consts import * +import sql +import time, json, re +from copy import copy +from threading import Timer + +####################################### Private methods +# Internal function for ApTimer, DO NOT CAST manually +# FIXME: Maybe find a better replacement for this +def ap_updater(token): + global ApTimer, Player + + # TODO: What if token is no longer valid? (Maybe use queue instead?) + Player[token]["ap"]+=1 + if (Player[token]["ap"] < Player[token]["max_ap"]): + try: + ApTimer[token].cancel() + del ApTimer[token] + except: + pass + ApTimer[token]=Timer(AP_REGEN_TIME_F, ap_updater, args=[token]) + ApTimer[token].daemon=True + ApTimer[token].start() + + return + +# Internal function for SQL, DO NOT CAST manually +def sql_routine(): + global Player, SQLTimer + + #stdout("Now saving SQL data") + for token in Player: + stdout("[SQL] Now saving token \"%s\"" % token) + stdout(str(Player[token])) + clear(token, SQL_DELAY) + + SQLTimer=Timer(SQL_SAVE_TIME, sql_routine) + SQLTimer.daemon=True + SQLTimer.start() + return + +# Attempts to place an item. Return inv index, -1 on error +def inventoryplace(token): + # Check for a free slot or return next index + try: + i=Player[token]["inv"].index(None) + except: + i=len(Player[token]["inv"]) + + # Return -1 if array exceeds the maximum size + if (i > MAX_INV_SIZE): + return -1 + else: + return i + +# Adds/Deletes AP from a user, manages the ApTimer +def update_ap(token, newval): + global ApTimer, Player + + running=False + if (Player[token]["ap"] < Player[token]["max_ap"]): + running=True + + # Update AP + # TODO: Do we allow over-the-cap AP? + Player[token]["ap"]+=newval + + # Handle the timer + if (not running and Player[token]["ap"] < Player[token]["max_ap"]): + ApTimer[token]=Timer(AP_REGEN_TIME_F, ap_updater, args=[token]) + ApTimer[token].daemon=True + ApTimer[token].start() + if (running and Player[token]["ap"] >= Player[token]["max_ap"]): + # If it is not running/error: We don't care (very rare error) + try: + ApTimer[token].cancel() + except: + pass + + return + +# Function which list all unit id on party +def party_dupcheck(token, pid): + ar=[] + for unt in Player[token]["party_%s" % pid]: + ar.append(unt["unit_id"]) + return ar + +# Function which list all unit id on inventory +def inv_dupcheck(token, unique=True): + ar=[] + for unt in Player[token]["inv"]: + if unt is None: + if unique: + continue + else: + ar.append(0) + else: + if unique: + if unt["unit_id"] in ar: + continue + else: + ar.append(unt["unit_id"]) + return ar + +# Techinically a battle function, readjusts a value +# Rarity affects directly primary stat. We should distribute 140 points +def readjust_status(rar, job, hp=True): + newv=50 + # Imbalanced class + if (job == Job_Swordsman): + if hp: + newv+=30+rar + else: + newv+=10+(rar/2) + elif (job == Job_Mage): + if hp: + newv+=10+(rar/2) + else: + newv+=30+rar + # Balanced class + elif (job == Job_Assassin): + if hp: + newv+=15+(rar/2) + else: + newv+=25+rar + elif (job == Job_Archer): + if hp: + newv+=25+rar + else: + newv+=15+(rar/2) + # All-rounder class, with no steady growth + elif (job == Job_Gunner): + if hp: + newv+=20+(rar/2) + else: + newv+=20+(rar/2) + + return newv + +def clear(token, mask=SQL_CLEAR): + # This function saves and clears a token + ######################################### + try: + # Save inventory data to SQL + sql.save_inv(token, mask) + + # Erase inventory if asked + if mask & SQL_CLEAR: + Player[token]["inv"]={} + + # Save party data to SQL + sql.save_party(token) + + # Erase parties if needed + if mask & SQL_CLEAR: + Player[token]["party_1"]={} + Player[token]["party_2"]={} + Player[token]["party_3"]={} + + # Now save Player data to SQL + sql.save_player(token, mask) + + # Erase Player Structure if needed + if mask & SQL_CLEAR: + del Player[token] + + # Stop the AP regeneration if we're clearing + if mask & SQL_CLEAR: + try: + ApTimer[token].cancel() + del ApTimer[token] + except: + pass + except: + stdout("SQL ERROR: FAILED TO CLEAR TOKEN %s" % token) + if mask & SQL_CLEAR: + del Player[token] + if mask & SQL_CLEAR: + try: + ApTimer[token].cancel() + del ApTimer[token] + except: + pass + + return + +def exp_to_lvlup(level): + # How much exp to rank up? + nmult=20.0 + nmult+=level/35.0 + nmult+=level/10.0 + nmult+=level/6.0 + nmult+=level/2.0 + nmult=nmult**1.01 + next_exp=int(level*nmult) + stdout("nmult is %.2f, exp needed: %d" % (nmult, next_exp)) + return next_exp + +# Check if player ranked up +# Return: {"code": True/False, "ap": <ap_raised>, "next": <exp_needed>} +def check_rank_up(token): + rs={"code": False, "ap": 0} + next_exp=exp_to_lvlup(Player[token]["level"])*2 + + if Player[token]["exp"] >= next_exp: + # We leveled up! Prepare the bonuses + rs["code"]=True + + # AP rules: Every 5 levels: +1 AP (always) + if Player[token]["level"] % 5 == 0: + rs["ap"]+=1 + # AP rules: Every 10 levels: +1 AP (always) + if Player[token]["level"] % 10 == 0: + rs["ap"]+=1 + # AP rules: Every level before the 20th: +1 AP (always_ + if Player[token]["level"] < 20: + rs["ap"]+=1 + + # Apply the level up + Player[token]["exp"]-=next_exp + Player[token]["level"]+=1 + Player[token]["max_ap"]+=rs["ap"] + update_ap(token, Player[token]["max_ap"]-Player[token]["ap"]) + + return rs + +# Conditional EXP attribution +# Doesn't returns anything +def grant_exp(token, inv_id, exp): + # We need some data + un=dl_search(allunits, "unit_id", Player[token]["inv"][inv_id]["unit_id"]) + if un == "ERROR": + stdout("WARNING, Invalid unit id on GEXP: %d" % (Player[token]["inv"][inv_id]["unit_id"])) + return + + # Max level, do nothing + if Player[token]["inv"][inv_id]["level"] >= un["max_level"]: + return + + Player[token]["inv"][inv_id]["exp"]+=exp + return + +# Same as check_rank_up but for units +# Returns True/False +def check_level_up(token, inv_id): + global allunits + + # Prepare un, the variable from unit database + un=dl_search(allunits, "unit_id", Player[token]["inv"][inv_id]["unit_id"]) + if un == "ERROR": + stdout("WARNING, Invalid unit id on CLU: %d" % (Player[token]["inv"][inv_id]["unit_id"])) + return -1 + + # FIX + if Player[token]["inv"][inv_id]["level"] > un["max_level"]: + stdout("WARNING, Overlevelled unit (Lv %d/%d)" % (Player[token]["inv"][inv_id]["level"], un["max_level"])) + Player[token]["inv"][inv_id]["exp"]=0 + Player[token]["inv"][inv_id]["level"]=copy(un["max_level"]) + + # Max level reached (FIXME why it still gets exp?!) + if Player[token]["inv"][inv_id]["level"] >= un["max_level"]: + return 0 + + # Calculate exp needed to level up + next_exp=exp_to_lvlup(Player[token]["inv"][inv_id]["level"]) + ret=0 + while Player[token]["inv"][inv_id]["exp"] >= next_exp: + ret += 1 + Player[token]["inv"][inv_id]["exp"]-=next_exp + Player[token]["inv"][inv_id]["level"]+=1 + # No overflow! + if Player[token]["inv"][inv_id]["level"] >= un["max_level"]: + Player[token]["inv"][inv_id]["exp"]=0 + Player[token]["inv"][inv_id]["level"]=copy(un["max_level"]) + break + next_exp=exp_to_lvlup(Player[token]["inv"][inv_id]["level"]) + return ret + +# Calculates sell price of an unit +# After 10 stars, the sell price overflows 10,000 and gets messy +# So I capped it at 10,000. Further stars will only raise level weight. +def calc_sell_price(rarity, level): + return min(10000, rarity**2*100)+(level*rarity) + +def daily_login(token): + # Prepare dates from player last login, and from now + # FIXME: "lastlogin" is updated in cycles + # If players pass midnight connected --> BOOM + # We should fill "lastlogin" at sql.load_player() only, instead of + # auto-updating it + dlcode=copy(ERR_LOGIN) + stdout("Last login: %s" % str(Player[token]["lastlogin"])) + + # dlcode mask: (ERR_LOGIN meaning) + # 5 - 0 - 0 - 0 + # ID - Monthly - Monthly - Weekly + + d,m,y,w,H,M=date_from_sql(str(Player[token]["lastlogin"])) + td,tm,ty,tw,tH,tM=date_from_now() + + # We don't really care with this bit of info + del H, M, tH, tM + + # It's not the same: A reward is due + if (d!=td or m!=tm or y!=ty): + dlcode+=1000 + + # TODO: Weekly rewards + if (w != tw) or (w == tw and (d != td or m != tm or y != ty)): + # A weekly reward is due! + dlcode+=tw + + if tw == MONDAY: + Player[token]["crystals"]+=50 + elif tw == TUESDAY: + Player[token]["crystals"]+=50 + elif tw == WEDNESDAY: + Player[token]["crystals"]+=50 + elif tw == THURSDAY: + Player[token]["crystals"]+=50 + elif tw == FRIDAY: + Player[token]["crystals"]+=50 + elif tw == SATURDAY: + Player[token]["crystals"]+=50 + elif tw == SUNDAY: + Player[token]["crystals"]+=50 + else: + stdout("ERROR ERROR, UNKNOWN DAY OF WEEK %d" % tw) + + # TODO: Monthly rewards + # TODO: Streak rewards + + # Finally, get rid of this data + del Player[token]["lastlogin"] + return dlcode + +####################################### Public methods (Player/Client) +def get_data(args, token): + stdout("Data received") + stdout("Now loading user ID: ```%s```" % str(args)) + try: + y=json.loads(args) + passwd=y["passwd"] + if not passwd.isalnum(): + raise Exception("Idiotic password") + if len(passwd) != 12: + raise Exception("Idiotic password") + vs=str(y["version"]) + except: + return ERR_BAD + + # Version check + if vs != CLIENTVERSION: + return ERR_OFF + + # Maybe this token is already loaded to memory? + # FIXME: The token is not secretive enough, someone with + # the "token" can bypass all auths, so this is a risk. + try: + Player[token]["status"]+=1 + Player[token]["status"]-=1 + Player[token]["code"]=ERR_LOGIN + Player[token]["token"]=token + stdout("Player is already logged in") + + # Delete user id, send payload, create user id again + uid=copy(Player[token]["userid"]) + del Player[token]["userid"] + paydata=compress(Player[token]) + Player[token]["userid"]=copy(uid) + del uid + + # Remove other temporary data + del Player[token]["code"] + del Player[token]["token"] + return paydata + except: + pass + + Player[token]=sql.load_player(token, passwd) + + # Maybe something went wrong, or password is invalid + if (Player[token] == ERR_BAD): + del Player[token] + return ERR_BAD + if (Player[token] == ERR_ERR): + del Player[token] + return ERR_ERR + + # Complete additional data + Player[token]["code"]=0 + Player[token]["token"]=token + + # Give you offline AP and refresh to NOW, round down + delta=(now()-Player[token]["aptime"])/AP_REGEN_TIME + Player[token]["ap"]=min(Player[token]["max_ap"], Player[token]["ap"]+delta) + Player[token]["aptime"]=now() + + # This is only to start the timer if needed + if (Player[token]["ap"] < Player[token]["max_ap"]): + ApTimer[token]=Timer(AP_REGEN_TIME_F, ap_updater, args=[token]) + ApTimer[token].daemon=True + ApTimer[token].start() + + # Daily login rewards + Player[token]["code"]=daily_login(token) + + # Remove UID from packet and save to JSON + uid=copy(Player[token]["userid"]) + del Player[token]["userid"] + sjson=compress(Player[token]) + Player[token]["userid"]=copy(uid) + + # Clear temporary data, write internal big data fields + del uid + del Player[token]["code"] + del Player[token]["token"] + Player[token]["inv"]=sql.load_inv(token) + Player[token]["party_1"]=sql.load_party(token, 1) + Player[token]["party_2"]=sql.load_party(token, 2) + Player[token]["party_3"]=sql.load_party(token, 3) + # TODO: Load currency table + # TODO: Load event table + + # Logged in + # {responseCode, token, status, gp, crystals, level, ap, max_ap, aptime } + return sjson + +# TODO: This returns the inventory. Should take a "page" argument +def get_inv(args, token): + sjson=compress(Player[token]["inv"]) + return sjson + +# Sell units. Receives a single JSON array of inventory IDs. +def sellunits(args, token): + try: + y=json.loads(args) + gp=0 + for tmp in y: + tmpa=int(tmp) + # Inventory size check (first check is not needed in a try loop...) + if tmpa >= len(Player[token]["inv"]): + raise Exception("Not in inventory") + if Player[token]["inv"][tmpa] == None: + stdout("None supplied (%d)" % tmpa) + raise Exception("Not in inventory") + + # UNSELLABLE flag + un=dl_search(allunits, "unit_id",Player[token]["inv"][tmpa]["unit_id"]) + if un["flags"] & UNSELLABLE: + stdout("This unit cannot be sold!") + raise Exception("This unit cannot be sold!") + + # No duplicates + if y.count(tmp) != 1: + stdout("Duplication detected: %d" % (args.count(tmp))) + raise Exception("Duplicate index detected") + + # Search in party + stdout("PARTY LOOKUP IN PROGRESS") + tmpb=dl_search(Player[token]["party_1"], "inv_id", tmpa) + if tmpb == "ERROR": + tmpb=dl_search(Player[token]["party_2"], "inv_id", tmpa) + if tmpb == "ERROR": + tmpb=dl_search(Player[token]["party_3"], "inv_id", tmpa) + if tmpb != "ERROR": + stdout("Unit is in party (%d)" % tmpb) + raise Exception("Party members can't be sold") + del tmpb + + # No point wasting time, we have "un" so sum GP as well + am=calc_sell_price(un["rare"], Player[token]["inv"][tmpa]["level"]) + if un["flags"] & DOUBLE_GP: + am*=2 + gp+=am + del un, am + del tmpa + except: + return ERR_BAD + + # Delete sold units and sum the GP + for idx in y: + Player[token]["inv"][idx]=None + Player[token]["gp"]+=int(gp) + sjson=compress('{"gp": %d, "profit": %d}' % (Player[token]["gp"], gp)) + return sjson + +# Upgrade units. Receives a JSON array: [UNIT-TO-UPGRADE, MAT1, MAT2, MAT3...] +# Based on invindex +def upgrade(args, token): + # Data validation (party members can't be used as material) + try: + y=json.loads(args) + w=False + for tmp in y: + tmpa=int(tmp) + # Inventory size check (first check is not needed in a try loop...) + if tmpa >= len(Player[token]["inv"]): + raise Exception("Not in inventory") + if Player[token]["inv"][tmpa] == None: + stdout("None supplied (%d)" % tmpa) + raise Exception("Not in inventory") + # First entry can be in the party, but must be uppable + if not w: + w=True + un=dl_search(allunits, "unit_id",Player[token]["inv"][tmpa]["unit_id"]) + stdout("Unit flags:") + stdout("%s" % un["flags"]) + #if un["flags"] & NO_LVLUP: # FIXME: Makes no sense now + # stdout("This unit cannot level up!") + # raise Exception("This unit cannot level up!") + target_ele=un["attribute"] + del un + continue + # Self fusion?? + stdout("begin: starting") + if y.count(tmp) != 1: + stdout("Duplication detected: %d" % (args.count(tmp))) + raise Exception("Duplicate index or self fusion detected") + # Search in party + stdout("LOOKUP IN PROGRESS") + tmpb=dl_search(Player[token]["party_1"], "inv_id", tmpa) + stdout("dl_search OK") + if tmpb == "ERROR": + tmpb=dl_search(Player[token]["party_2"], "inv_id", tmpa) + if tmpb == "ERROR": + tmpb=dl_search(Player[token]["party_3"], "inv_id", tmpa) + if tmpb != "ERROR": + stdout("Unit is in party (%d)" % tmpb) + raise Exception("Party members can't be used as material") + del tmpb + del tmpa, w + except: + return ERR_BAD + + # Get "target" inv id + target=y.pop(0) + stdout("Target is (%d)" % target) + + # Define the experience you'll get by draining the relevant indexes + xp=0 + for idx in y: + uxp=0 + ud=Player[token]["inv"][idx]["unit_id"] + un=dl_search(allunits, "unit_id", ud) + try: + r=un["rare"] + f=un["flags"] + e=un["attribute"] + next_exp=exp_to_lvlup(Player[token]["inv"][idx]["level"]) + except: + r=1 + f=0 + e=-1 + stdout("ERROR, INVALID UNIT ID: %d" % ud) + + # Units with EXP_UP are always "max-level" + if f & EXP_UP: + lv=10+(r*10) + else: + lv=Player[token]["inv"][idx]["level"] + + uxp+=lv*20.0*((r+1)/2.0) + uxp+=Player[token]["inv"][idx]["exp"]/next_exp*100.0*20.0 + + # Flags and same element bonus + if f & EXP_UP: + uxp*=1.5 + if e == target_ele: + uxp*=1.2 + + # Give the exp, and remove from inventory + xp+=int(uxp) + Player[token]["inv"][idx]=None + + # We now have the experience, so we grant it + grant_exp(token, target, xp) + r=check_level_up(token, target) + + sjson=compress(r) + return sjson + +# args is the party ID +def get_party(args, token): + try: + pid=int(args) + if (pid > MAX_PARTIES): + raise Exception("too many parties") + except: + return ERR_BAD + + sjson=compress(Player[token]["party_%d" % pid]) + return sjson + +# TODO: Obviously this is also a WIP +# {"party_id": pid, "formation": [p1, p2, p3, p4]} +def set_party(args, token): + # Standard checks + try: + y=json.loads(args) + tmp=y["party_id"] + pid=int(tmp) + # Maximum party number + if (pid > MAX_PARTIES): + raise Exception("too many parties") + # Only integers + for ele in y["formation"]: + tmp=int(ele) + # If the unit is not valid (in inventory), this will EXPLODE + un=dl_search(allunits, "unit_id", Player[token]["inv"][tmp]["unit_id"]) + if un["flags"] & NO_PARTY: + raise Exception("This unit cannot be part of a party!") + del un + except: + return ERR_BAD + + # FIXME: We can't have duplicates Oh My :o + #Player[token]["party_1"]=[] + stdout("Request to edit party %d" % pid) + + # Check each request before appending + for i, idx in enumerate(y["formation"]): + stdout("Now checking (%d, %d)" % (i, idx)) + + # Empty the index in analysis + Player[token]["party_%s" % pid][i]={"unit_id": 0, + "inv_id": -1} + + # Ignored index + if (idx < 0): + continue + + # Duplicate checking! + if (Player[token]["inv"][idx]["unit_id"] in party_dupcheck(token, pid)): + return ERR_BAD + + # Retrieve inventory data and replace it in player tokens + Player[token]["party_%s" % pid][i]["unit_id"]=Player[token]["inv"][idx]["unit_id"] + Player[token]["party_%s" % pid][i]["inv_id"]=idx + + return ERR_DONE + +# Evolve units. Receives a JSON array: [UNIT-TO-EVOLVE, MAT1, MAT2] +# Based on invindex +def evolve(args, token): + # Data validation (party members can't be used as material) + try: + y=json.loads(args) + if len(y) != 3: + return ERR_BAD + w=False + for tmp in y: + tmpa=int(tmp) + # Inventory size check (first check is not needed in a try loop...) + if tmpa >= len(Player[token]["inv"]): + raise Exception("Not in inventory") + if Player[token]["inv"][tmpa] == None: + stdout("None supplied (%d)" % tmpa) + raise Exception("Not in inventory") + # First entry can be in the party, but must be MAX LEVEL and level-able + if not w: + w=True + un=dl_search(allunits, "unit_id",Player[token]["inv"][tmpa]["unit_id"]) + stdout("Unit flags:") + stdout("%s" % un["flags"]) + #if un["flags"] & NO_LVLUP: # FIXME: Makes no sense now + # stdout("This unit cannot level up!") + # raise Exception("This unit cannot level up!") + if un["max_level"] != Player[token]["inv"][tmpa]["level"]: + stdout("raise: Level not yet maxed") + raise Exception("Not yet max level!") + target_ele=un["attribute"] + target_id=un["unit_id"] + target_rare=un["rare"] + # Check if evolved version exists + evolved=dl_search(allunits, "unit_id",Player[token]["inv"][tmpa]["unit_id"]+1) + evolved_id=evolved["unit_id"] # Same as raise Exception if can't evolve + del un + continue + # Self fusion?? + stdout("begin: starting") + if y.count(tmp) != 1: + stdout("Duplication detected: %d" % (args.count(tmp))) + raise Exception("Duplicate index or self fusion detected") + # Search in party + stdout("LOOKUP IN PROGRESS") + tmpb=dl_search(Player[token]["party_1"], "inv_id", tmpa) + stdout("dl_search OK") + if tmpb == "ERROR": + tmpb=dl_search(Player[token]["party_2"], "inv_id", tmpa) + if tmpb == "ERROR": + tmpb=dl_search(Player[token]["party_3"], "inv_id", tmpa) + if tmpb != "ERROR": + stdout("Unit is in party (%d)" % tmpb) + raise Exception("Party members can't be used as material") + # TODO: Check if it is suitable material (same rarity etc.) + r=False + tmpb=dl_search(allunits, "unit_id",Player[token]["inv"][tmpa]["unit_id"]) + if tmpb["rare"] == target_rare: + if tmpb["flags"] & SUPEREVOMAT: + r=True + elif tmpb["flags"] & EVO_MAT: + if tmpb["attribute"] == target_ele: + r=True + elif tmpb["unit_id"] == target_id: + r=True + if not r: + stdout("raise: Invalid evolution material") + raise Exception("Invalid evolve material") + del tmpb + del tmpa, w + except: + return ERR_BAD + + # Get "target" inv id + #target=y.pop(0) + stdout("Target is (%d)" % target_id) + + # Evolve and remove material. Clear level/exp as well. + Player[token]["inv"][y[0]]["unit_id"]+=1 + Player[token]["inv"][y[0]]["level"]=0 + Player[token]["inv"][y[0]]["exp"]=0 + Player[token]["inv"][y[1]]=None + Player[token]["inv"][y[2]]=None + r=ERR_OK + + # TODO: Update party, NOT high priority + try: + tmpb=dl_search(Player[token]["party_1"], "inv_id", target_id) + if tmpb != "ERROR": + tmpb["unit_id"]+=1 + + tmpb=dl_search(Player[token]["party_2"], "inv_id", target_id) + if tmpb != "ERROR": + tmpb["unit_id"]+=1 + + tmpb=dl_search(Player[token]["party_3"], "inv_id", target_id) + if tmpb != "ERROR": + tmpb["unit_id"]+=1 + + # Now, do this cause a duplicate? If yes, unsocket it! + tmpa=0 + for tmpb in Player[token]["party_1"]: + if tmpb["unit_id"] == evolved_id: + tmpa+=1 + if tmpa > 1: + tmpb["unit_id"]=-1 + tmpb["inv_id"]=-1 + stdout("Unsocket") + + tmpa=0 + for tmpb in Player[token]["party_2"]: + if tmpb["unit_id"] == evolved_id: + tmpa+=1 + if tmpa > 1: + tmpb["unit_id"]=-1 + tmpb["inv_id"]=-1 + stdout("Unsocket") + + tmpa=0 + for tmpb in Player[token]["party_3"]: + if tmpb["unit_id"] == evolved_id: + tmpa+=1 + if tmpa > 1: + tmpb["unit_id"]=-1 + tmpb["inv_id"]=-1 + stdout("Unsocket") + + except: + pass + + sjson=compress(r) + return sjson + + +# Creates a new account. Arguments: email +def register(args, token): + stdout("Request to register an account: %s" % str(args)) + # https://emailregex.com/email-validation-summary/ - RFC allows more emails + # But we don't want to risk compromising the database, and some are dump + regex = '^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$' + try: + y=json.loads(args) + tmp=y["email"] + mail=str(tmp) + # Check if email is valid with above regex + if not re.search(regex,mail): + raise Exception("Not a valid email") + except: + return ERR_BAD + + # TODO: "duplicate": all emails which difference consists on ponctuation + #email=mail.replace(".", "").replace("_", "").replace("-", "").replace("+", "") + + stdout("Initial checks succeded") + # Check if email is already registered + check=sql.query_email(mail) + if (check != ""): + stdout("WARNING: Tried to register email \"%s\" (belongs to account %s)" % (mail, check)) + return ERR_BAD + + stdout("Now registering account") + # Register it + data=sql.add_player(mail) + if (data["userid"] <= 0): + return ERR_ERR + + # From data, we have: userid, password + return compress(data) + + |