/*========================================== * Create subscription timer for party *------------------------------------------*/ static int instance_subscription_timer(int tid, unsigned int tick, int id, intptr_t data) { int i, ret; int instance_id = instance_wait.id[0]; struct party_data *p; if(instance_wait.count == 0 || instance_id <= 0) return 0; // Check that maps have been added ret = instance_addmap(instance_id); // If no maps are created, tell party to wait if(ret == 0 && (p = party_search(instance_data[instance_id].party_id)) != NULL) clif_instance_changewait(party_getavailablesd(p), 0xffff, 1); instance_wait.count--; memmove(&instance_wait.id[0], &instance_wait.id[1], sizeof(instance_wait.id[0]) * instance_wait.count); memset(&instance_wait.id[instance_wait.count], 0, sizeof(instance_wait.id[0])); for(i = 0; i < instance_wait.count; i++) { if(instance_data[instance_wait.id[i]].state == INSTANCE_IDLE && (p = party_search(instance_data[instance_wait.id[i]].party_id)) != NULL) clif_instance_changewait(party_getavailablesd(p), i + 1, 1); } if(instance_wait.count) instance_wait.timer = add_timer(gettick() + INSTANCE_INTERVAL, instance_subscription_timer, 0, 0); else instance_wait.timer = INVALID_TIMER; return 0; }
/*-------------------------------------- * Adds maps to the instance *--------------------------------------*/ int instance_addmap(short instance_id) { int i, m; int cnt_map = 0; struct instance_data *im; struct instance_db *db; struct party_data *p; if(instance_id <= 0) return 0; im = &instance_data[instance_id]; // If the instance isn't idle, we can't do anything if(im->state != INSTANCE_IDLE) return 0; if((db = instance_searchtype_db(im->type)) == NULL) return 0; // Set to busy, update timers im->state = INSTANCE_BUSY; im->idle_limit = (unsigned int)time(NULL) + INSTANCE_LIMIT / 1000; im->idle_timer = add_timer(gettick() + INSTANCE_LIMIT, instance_delete_timer, instance_id, 0); // Add the maps for(i = 0; i < db->maplist_count; i++) { if(strlen(StringBuf_Value(db->maplist[i])) < 1) continue; else if((m = map_addinstancemap(StringBuf_Value(db->maplist[i]), instance_id)) < 0) { // An error occured adding a map ShowError("instance_addmap: No maps added to instance %d.\n",instance_id); return 0; } else { im->map[cnt_map].m = m; im->map[cnt_map].src_m = map_mapname2mapid(StringBuf_Value(db->maplist[i])); cnt_map++; } } im->cnt_map = cnt_map; // Create NPCs on all maps instance_addnpc(im); // Inform party members of the created instance if((p = party_search(im->party_id)) != NULL) clif_instance_status(party_getavailablesd(p), StringBuf_Value(db->name), im->keep_limit, im->idle_limit, 1); return cnt_map; }
/// Invoked (from char-server) when a party member leaves the party. int party_member_withdraw(int party_id, uint32 account_id, uint32 char_id, char *name, enum e_party_member_withdraw type) { struct map_session_data* sd = map_charid2sd(char_id); struct party_data* p = party_search(party_id); if( p ) { int i; clif_party_withdraw(party_getavailablesd(p), account_id, name, type, PARTY); ARR_FIND( 0, MAX_PARTY, i, p->party.member[i].account_id == account_id && p->party.member[i].char_id == char_id ); if( i < MAX_PARTY ) { memset(&p->party.member[i], 0, sizeof(p->party.member[0])); memset(&p->data[i], 0, sizeof(p->data[0])); p->party.count--; party_check_state(p); } } if( sd && sd->status.party_id == party_id ) { #ifdef BOUND_ITEMS int idxlist[MAX_INVENTORY]; //or malloc to reduce consumtion int j,i; party_trade_bound_cancel(sd); j = pc_bound_chk(sd,BOUND_PARTY,idxlist); for(i = 0; i < j; i++) pc_delitem(sd,idxlist[i],sd->inventory.u.items_inventory[idxlist[i]].amount,0,1,LOG_TYPE_BOUND_REMOVAL); #endif sd->status.party_id = 0; clif_name_area(&sd->bl); //Update name display [Skotlex] //TODO: hp bars should be cleared too if( p->instance_id ) { struct map_data *mapdata = map_getmapdata(sd->bl.m); if( mapdata->instance_id ) { // User was on the instance map if( mapdata->save.map ) pc_setpos(sd, mapdata->save.map, mapdata->save.x, mapdata->save.y, CLR_TELEPORT); else pc_setpos(sd, sd->status.save_point.map, sd->status.save_point.x, sd->status.save_point.y, CLR_TELEPORT); } } } return 0; }
/*-------------------------------------- * name : instance name * Return value could be * -4 = no free instances | -3 = already exists | -2 = party not found | -1 = invalid type * On success return instance_id *--------------------------------------*/ int instance_create(int party_id, const char *name) { short i; struct instance_db *db = instance_searchname_db(name); struct party_data *p = party_search(party_id); if(db == NULL) return -1; if(p == NULL) return -2; if(p->instance_id) return -3; // Party already instancing // Searching a Free Instance // 0 is ignored as this mean "no instance" on maps ARR_FIND(1, MAX_INSTANCE_DATA, i, instance_data[i].state == INSTANCE_FREE); if(i >= MAX_INSTANCE_DATA) return -4; instance_data[i].type = db->id; instance_data[i].state = INSTANCE_IDLE; instance_data[i].party_id = p->party.party_id; instance_data[i].keep_limit = 0; instance_data[i].keep_timer = INVALID_TIMER; instance_data[i].idle_limit = 0; instance_data[i].idle_timer = INVALID_TIMER; instance_data[i].vars = idb_alloc(DB_OPT_RELEASE_DATA); memset(instance_data[i].map, 0, sizeof(instance_data[i].map)); p->instance_id = i; instance_wait.id[instance_wait.count++] = p->instance_id; clif_instance_create(party_getavailablesd(p), name, instance_wait.count, 1); instance_subscription_timer(0, 0, 0, 0); ShowInfo("[Instance] Created: %s.\n", name); return i; }
/*========================================== * Delete the idle timer *------------------------------------------*/ static int instance_stopidletimer(struct instance_data *im) { struct party_data *p; nullpo_retr(0, im); // No timer if(im->idle_timer == INVALID_TIMER) return 1; // Delete the timer - Party has returned or instance is destroyed im->idle_limit = 0; delete_timer(im->idle_timer, instance_delete_timer); im->idle_timer = INVALID_TIMER; // Notify the party if((p = party_search(im->party_id)) != NULL) clif_instance_changestatus(party_getavailablesd(p), 0, im->idle_limit, 1); return 0; }
/*========================================== * Creates idle timer * Default before instance destroy is 5 minutes *------------------------------------------*/ static int instance_startidletimer(struct instance_data *im, short instance_id) { struct instance_db *db; struct party_data *p; nullpo_retr(1, im); // No current timer if(im->idle_timer != INVALID_TIMER) return 1; // Add the timer im->idle_limit = (unsigned int)time(NULL) + INSTANCE_LIMIT / 1000; im->idle_timer = add_timer(gettick()+INSTANCE_LIMIT, instance_delete_timer, instance_id, 0); // Notify party of added instance timer if((p = party_search(im->party_id)) != NULL && (db = instance_searchtype_db(im->type)) != NULL) clif_instance_status(party_getavailablesd(p), StringBuf_Value(db->name), im->keep_limit, im->idle_limit, 1); return 0; }
/*========================================== * Adds timer back to party entering instance *------------------------------------------*/ static int instance_startkeeptimer(struct instance_data *im, short instance_id) { struct instance_db *db; struct party_data *p; nullpo_retr(0, im); // No timer if(im->keep_timer != -1) return 1; if((db = instance_searchtype_db(im->type)) == NULL) return 1; // Add timer im->keep_limit = (unsigned int)time(NULL) + db->limit; im->keep_timer = add_timer(gettick()+db->limit*1000, instance_delete_timer, instance_id, 0); // Notify party of the added instance timer if( ( p = party_search( im->party_id ) ) != NULL ) clif_instance_status( party_getavailablesd( p ), db->name, im->keep_limit, im->idle_limit, 1 ); return 0; }
/*========================================== * Removes a instance, all its maps and npcs. *------------------------------------------*/ int instance_destroy(short instance_id) { struct instance_data *im; struct party_data *p; int i, type = 0; unsigned int now = (unsigned int)time(NULL); if(instance_id <= 0 || instance_id > MAX_INSTANCE_DATA) return 1; im = &instance_data[instance_id]; if(im->state == INSTANCE_FREE) return 1; if(im->state == INSTANCE_IDLE) { for(i = 0; i < instance_wait.count; i++) { if(instance_wait.id[i] == instance_id) { instance_wait.count--; memmove(&instance_wait.id[i], &instance_wait.id[i + 1], sizeof(instance_wait.id[0]) * (instance_wait.count - i)); memset(&instance_wait.id[instance_wait.count], 0, sizeof(instance_wait.id[0])); for(i = 0; i < instance_wait.count; i++) { if(instance_data[instance_wait.id[i]].state == INSTANCE_IDLE && (p = party_search(instance_data[instance_wait.id[i]].party_id)) != NULL) clif_instance_changewait(party_getavailablesd(p), i + 1, 1); } if(instance_wait.count) instance_wait.timer = add_timer(gettick() + INSTANCE_INTERVAL, instance_subscription_timer, 0, 0); else instance_wait.timer = INVALID_TIMER; type = 0; break; } } } else { if(im->keep_limit && im->keep_limit <= now) type = 1; else if(im->idle_limit && im->idle_limit <= now) type = 2; else type = 3; for(i = 0; i < MAX_MAP_PER_INSTANCE; i++) map_delinstancemap(im->map[i].m); } if(im->keep_timer != INVALID_TIMER) { delete_timer(im->keep_timer, instance_delete_timer); im->keep_timer = INVALID_TIMER; } if(im->idle_timer != INVALID_TIMER) { delete_timer(im->idle_timer, instance_delete_timer); im->idle_timer = INVALID_TIMER; } if((p = party_search(im->party_id))) { p->instance_id = 0; if(type) clif_instance_changestatus(party_getavailablesd(p), type, 0, 1); else clif_instance_changewait(party_getavailablesd(p), 0xffff, 1); } if(im->vars) { db_destroy(im->vars); im->vars = NULL; } ShowInfo("[Instance] Destroyed %d.\n", instance_id); memset(&instance_data[instance_id], 0, sizeof(instance_data[instance_id])); return 0; }