Exemple #1
0
/*==========================================
 * Divorce request from char server
 * triggered on account deletion or as an
 * ack from a map-server divorce request
 *------------------------------------------
 */
static
int chrif_divorce(CharId char_id, CharId partner_id)
{
    dumb_ptr<map_session_data> sd = nullptr;

    if (!char_id || !partner_id)
        return 0;

    sd = map_nick2sd(map_charid2nick(char_id));
    if (sd && sd->status.partner_id == partner_id)
    {
        sd->status.partner_id = CharId();

        if (sd->npc_flags.divorce)
        {
            sd->npc_flags.divorce = 0;
            map_scriptcont(sd, sd->npc_id);
        }
    }

    sd = map_nick2sd(map_charid2nick(partner_id));
    nullpo_retz(sd);
    if (sd->status.partner_id == char_id)
        sd->status.partner_id = CharId();

    return 0;
}
Exemple #2
0
// パーティ除名要求
int party_removemember(dumb_ptr<map_session_data> sd, AccountId account_id)
{
    PartyPair p;
    int i;

    nullpo_retz(sd);

    if (!(p = party_search(sd->status.party_id)))
        return 0;

    for (i = 0; i < MAX_PARTY; i++)
    {                           // リーダーかどうかチェック
        if (p->member[i].account_id == sd->status_key.account_id)
        {
            if (p->member[i].leader == 0)
                return 0;
        }
    }

    for (i = 0; i < MAX_PARTY; i++)
    {                           // 所属しているか調べる
        if (p->member[i].account_id == account_id)
        {
            intif_party_leave(p.party_id, account_id);
            return 0;
        }
    }
    return 0;
}
Exemple #3
0
/*==========================================
 * (x,y)が移動不可能地帯かどうか
 * flag 0x10000 遠距離攻撃判定
 *------------------------------------------
 */
static
bool can_place(struct map_local *m, int x, int y)
{
    nullpo_retz(m);

    return !bool(read_gatp(m, x, y) & MapCell::UNWALKABLE);
}
Exemple #4
0
// パーティメンバの移動
int party_send_movemap(dumb_ptr<map_session_data> sd)
{
    PartyPair p;

    nullpo_retz(sd);

    if (!sd->status.party_id)
        return 0;
    intif_party_changemap(sd, 1);

    if (sd->party_sended != 0)  // もうパーティデータは送信済み
        return 0;

    // 競合確認
    party_check_conflict(sd);

    // あるならパーティ情報送信
    if ((p = party_search(sd->status.party_id)))
    {
        party_check_member(p); // 所属を確認する
        if (sd->status.party_id == p.party_id)
        {
            clif_party_info(p, sd->sess);
            clif_party_option(p, sd, 0x100);
            sd->party_sended = 1;
        }
    }

    return 0;
}
Exemple #5
0
/* Process response to party invitation. */
int party_reply_invite(dumb_ptr<map_session_data> sd, AccountId account_id, int flag)
{
    nullpo_retz(sd);

    /* There is no pending invitation. */
    if (!sd->party_invite || !sd->party_invite_account)
        return 0;

    /*
     * Only one invitation can be pending, so these have to be the same. Since
     * the client continues to send the wrong ID, and it's already managed on
     * this side of things, the sent ID is being ignored.
     */
    account_id = sd->party_invite_account;

    /* The invitation was accepted. */
    if (flag == 1)
        intif_party_addmember(sd->party_invite, sd->status_key.account_id);
    /* The invitation was rejected. */
    else
    {
        /* This is the player who sent the invitation. */
        dumb_ptr<map_session_data> tsd = nullptr;

        sd->party_invite = PartyId();
        sd->party_invite_account = AccountId();

        if ((tsd = map_id2sd(account_to_block(account_id))))
            clif_party_inviteack(tsd, sd->status_key.name, 1);
    }
    return 0;
}
Exemple #6
0
/*==========================================
 * 必要ならpathを追加/修正する
 *------------------------------------------
 */
static
int add_path(int *heap, struct tmp_path *tp, int x, int y, int dist,
        DIR dir, int before, int x1, int y1)
{
    int i;

    nullpo_retz(heap);
    nullpo_retz(tp);

    i = calc_index(x, y);

    if (tp[i].x == x && tp[i].y == y)
    {
        if (tp[i].dist > dist)
        {
            tp[i].dist = dist;
            tp[i].dir = dir;
            tp[i].before = before;
            tp[i].cost = calc_cost(&tp[i], x1, y1);
            if (tp[i].flag)
                push_heap_path(heap, tp, i);
            else
                update_heap_path(heap, tp, i);
            tp[i].flag = 0;
        }
        return 0;
    }

    if (tp[i].x || tp[i].y)
        return 1;

    tp[i].x = x;
    tp[i].y = y;
    tp[i].dist = dist;
    tp[i].dir = dir;
    tp[i].before = before;
    tp[i].cost = calc_cost(&tp[i], x1, y1);
    tp[i].flag = 0;
    push_heap_path(heap, tp, i);

    return 0;
}
Exemple #7
0
/*==========================================
 * カプラ倉庫を開く
 *------------------------------------------
 */
int storage_storageopen(dumb_ptr<map_session_data> sd)
{
    nullpo_retz(sd);

    if (sd->state.storage_open)
        return 1;               //Already open?

    P<Storage> stor = TRY_UNWRAP(storage_db.search(sd->status_key.account_id),
    {                           //Request storage.
        intif_request_storage(sd->status_key.account_id);
        return 1;
    });
Exemple #8
0
// パーティの設定変更要求
int party_changeoption(dumb_ptr<map_session_data> sd, int exp, int item)
{
    PartyPair p;

    nullpo_retz(sd);

    if (!sd->status.party_id
        || !(p = party_search(sd->status.party_id)))
        return 0;
    intif_party_changeoption(sd->status.party_id, sd->status_key.account_id, exp,
                              item);
    return 0;
}
Exemple #9
0
/*==========================================
 * 現在の点のcost計算
 *------------------------------------------
 */
static
int calc_cost(struct tmp_path *p, int x1, int y1)
{
    int xd, yd;

    nullpo_retz(p);

    xd = x1 - p->x;
    if (xd < 0)
        xd = -xd;
    yd = y1 - p->y;
    if (yd < 0)
        yd = -yd;
    return (xd + yd) * 10 + p->dist;
}
Exemple #10
0
/* Process a party creation request. */
int party_create(dumb_ptr<map_session_data> sd, PartyName name)
{
    nullpo_retz(sd);

    name = stringish<PartyName>(name.strip());

    /* The party name is empty/invalid. */
    if (!name)
        clif_party_created(sd, 1);

    /* Make sure the character isn't already in a party. */
    if (!sd->status.party_id)
        intif_create_party(sd, name);
    else
        clif_party_created(sd, 2);

    return 0;
}
Exemple #11
0
/*==========================================
 * (x0,y0)から(x1,y1)へ1歩で移動可能か計算
 *------------------------------------------
 */
static
int can_move(struct map_local *m, int x0, int y0, int x1, int y1)
{
    nullpo_retz(m);

    if (x0 - x1 < -1 || x0 - x1 > 1 || y0 - y1 < -1 || y0 - y1 > 1)
        return 0;
    if (x1 < 0 || y1 < 0 || x1 >= m->xs || y1 >= m->ys)
        return 0;
    if (!can_place(m, x0, y0))
        return 0;
    if (!can_place(m, x1, y1))
        return 0;
    if (x0 == x1 || y0 == y1)
        return 1;
    if (!can_place(m, x0, y1) || !can_place(m, x1, y0))
        return 0;
    return 1;
}
Exemple #12
0
/*==========================================
 * イベントキューのイベント処理
 *------------------------------------------
 */
int npc_event_dequeue(dumb_ptr<map_session_data> sd)
{
    nullpo_retz(sd);

    sd->npc_id = BlockId();

    if (!sd->eventqueuel.empty())
    {
        if (!pc_addeventtimer(sd, 100_ms, sd->eventqueuel.front()))
        {
            PRINTF("npc_event_dequeue(): Event timer is full.\n"_fmt);
            return 0;
        }

        sd->eventqueuel.pop_front();
        return 1;
    }

    return 0;
}
Exemple #13
0
// パーティメンバのログアウト
int party_send_logout(dumb_ptr<map_session_data> sd)
{
    PartyPair p;

    nullpo_retz(sd);

    if (sd->status.party_id)
        intif_party_changemap(sd, 0);

    // sdが無効になるのでパーティ情報から削除
    if ((p = party_search(sd->status.party_id)))
    {
        int i;
        for (i = 0; i < MAX_PARTY; i++)
            if (dumb_ptr<map_session_data>(p->member[i].sd) == sd)
                p->member[i].sd = nullptr;
    }

    return 0;
}
Exemple #14
0
// パーティ脱退要求
int party_leave(dumb_ptr<map_session_data> sd)
{
    PartyPair p;
    int i;

    nullpo_retz(sd);

    if (!(p = party_search(sd->status.party_id)))
        return 0;

    for (i = 0; i < MAX_PARTY; i++)
    {                           // 所属しているか
        if (p->member[i].account_id == sd->status_key.account_id)
        {
            intif_party_leave(p.party_id, sd->status_key.account_id);
            return 0;
        }
    }
    return 0;
}
Exemple #15
0
// 所属キャラの確認
static
int party_check_member(PartyPair p)
{
    nullpo_retz(p);

    for (io::FD i : iter_fds())
    {
        Session *s = get_session(i);
        if (!s)
            continue;
        map_session_data *sd = static_cast<map_session_data *>(s->session_data.get());
        if (sd && sd->state.auth)
        {
            if (sd->status.party_id == p.party_id)
            {
                int j, f = 1;
                for (j = 0; j < MAX_PARTY; j++)
                {               // パーティにデータがあるか確認
                    if (p->member[j].account_id == sd->status_key.account_id)
                    {
                        if (p->member[j].name == sd->status_key.name)
                            f = 0;  // データがある
                        else
                        {
                            // I can prove it was already zeroed
                            // p->member[j].sd = nullptr; // 同垢別キャラだった
                        }
                    }
                }
                if (f)
                {
                    sd->status.party_id = PartyId();
                    if (battle_config.error_log)
                        PRINTF("party: check_member %d[%s] is not member\n"_fmt,
                                sd->status_key.account_id, sd->status_key.name);
                }
            }
        }
    }
    return 0;
}
Exemple #16
0
// 情報所得
int party_recv_info(const PartyPair sp)
{
    int i;

    nullpo_retz(sp);

    PartyPair p = party_search(sp.party_id);
    if (!p)
    {
        p.party_most = party_db.init(sp.party_id);

        // 最初のロードなのでユーザーのチェックを行う
        *p.party_most = *sp.party_most;
        party_check_member(p);
    }
    else
        *p.party_most = *sp.party_most;

    for (i = 0; i < MAX_PARTY; i++)
    {                           // sdの設定
        dumb_ptr<map_session_data> sd = map_id2sd(account_to_block(p->member[i].account_id));
        p->member[i].sd = (sd != nullptr
                           && sd->status.party_id == p.party_id) ? sd.operator->() : nullptr;
    }

    clif_party_info(p, nullptr);

    for (i = 0; i < MAX_PARTY; i++)
    {                           // 設定情報の送信
//      dumb_ptr<map_session_data> sd = map_id2sd(p->member[i].account_id);
        dumb_ptr<map_session_data> sd = dumb_ptr<map_session_data>(p->member[i].sd);
        if (sd != nullptr && sd->party_sended == 0)
        {
            clif_party_option(p, sd, 0x100);
            sd->party_sended = 1;
        }
    }

    return 0;
}
Exemple #17
0
// 経験値公平分配
int party_exp_share(PartyPair p, map_local *mapid, int base_exp, int job_exp)
{
    dumb_ptr<map_session_data> sd;
    int i, c;

    nullpo_retz(p);

    for (i = c = 0; i < MAX_PARTY; i++)
    {
        sd = dumb_ptr<map_session_data>(p->member[i].sd);
        if (sd != nullptr && sd->bl_m == mapid)
            c++;
    }
    if (c == 0)
        return 0;
    for (i = 0; i < MAX_PARTY; i++)
    {
        sd = dumb_ptr<map_session_data>(p->member[i].sd);
        if (sd != nullptr && sd->bl_m == mapid)
            pc_gainexp_reason(sd, base_exp / c + 1, job_exp / c + 1,
            PC_GAINEXP_REASON::SHARING);
    }
    return 0;
}
Exemple #18
0
/*==========================================
 * path探索 (x0,y0)->(x1,y1)
 *------------------------------------------
 */
int path_search(struct walkpath_data *wpd, map_local *m, int x0, int y0, int x1, int y1, int flag)
{
    int heap[MAX_HEAP + 1];
    int i, rp, x, y;
    int dx, dy;

    nullpo_retz(wpd);

    assert (m->gat);
    map_local *md = m;
    if (x1 < 0 || x1 >= md->xs || y1 < 0 || y1 >= md->ys
        || bool(read_gatp(md, x1, y1) & MapCell::UNWALKABLE))
        return -1;

    // easy
    dx = (x1 - x0 < 0) ? -1 : 1;
    dy = (y1 - y0 < 0) ? -1 : 1;
    for (x = x0, y = y0, i = 0; x != x1 || y != y1;)
    {
        if (i >= sizeof(wpd->path))
            return -1;
        if (x != x1 && y != y1)
        {
            if (!can_move(md, x, y, x + dx, y + dy))
                break;
            x += dx;
            y += dy;
            wpd->path[i++] = (dx < 0)
                ? ((dy > 0) ? DIR::SW : DIR::NW)
                : ((dy < 0) ? DIR::NE : DIR::SE);
        }
        else if (x != x1)
        {
            if (!can_move(md, x, y, x + dx, y))
                break;
            x += dx;
            wpd->path[i++] = (dx < 0) ? DIR::W : DIR::E;
        }
        else
        {                       // y!=y1
            if (!can_move(md, x, y, x, y + dy))
                break;
            y += dy;
            wpd->path[i++] = (dy > 0) ? DIR::S : DIR::N;
        }
        if (x == x1 && y == y1)
        {
            wpd->path_len = i;
            wpd->path_pos = 0;
            wpd->path_half = 0;
            return 0;
        }
    }
    if (flag & 1)
        return -1;

    struct tmp_path tp[MAX_WALKPATH * MAX_WALKPATH] {};

    i = calc_index(x0, y0);
    tp[i].x = x0;
    tp[i].y = y0;
    tp[i].dist = 0;
    tp[i].dir = DIR::S;
    tp[i].before = 0;
    tp[i].cost = calc_cost(&tp[i], x1, y1);
    tp[i].flag = 0;
    heap[0] = 0;
    push_heap_path(heap, tp, calc_index(x0, y0));
    while (1)
    {
        int e = 0;

        if (heap[0] == 0)
            return -1;
        rp = pop_heap_path(heap, tp);
        x = tp[rp].x;
        y = tp[rp].y;
        if (x == x1 && y == y1)
        {
            int len, j;

            for (len = 0, i = rp; len < 100 && i != calc_index(x0, y0);
                 i = tp[i].before, len++);
            if (len == 100 || len >= sizeof(wpd->path))
                return -1;
            wpd->path_len = len;
            wpd->path_pos = 0;
            wpd->path_half = 0;
            for (i = rp, j = len - 1; j >= 0; i = tp[i].before, j--)
                wpd->path[j] = tp[i].dir;

            return 0;
        }
        if (can_move(md, x, y, x + 1, y - 1))
            e += add_path(heap, tp, x + 1, y - 1, tp[rp].dist + 14, DIR::NE, rp, x1, y1);
        if (can_move(md, x, y, x + 1, y))
            e += add_path(heap, tp, x + 1, y, tp[rp].dist + 10, DIR::E, rp, x1, y1);
        if (can_move(md, x, y, x + 1, y + 1))
            e += add_path(heap, tp, x + 1, y + 1, tp[rp].dist + 14, DIR::SE, rp, x1, y1);
        if (can_move(md, x, y, x, y + 1))
            e += add_path(heap, tp, x, y + 1, tp[rp].dist + 10, DIR::S, rp, x1, y1);
        if (can_move(md, x, y, x - 1, y + 1))
            e += add_path(heap, tp, x - 1, y + 1, tp[rp].dist + 14, DIR::SW, rp, x1, y1);
        if (can_move(md, x, y, x - 1, y))
            e += add_path(heap, tp, x - 1, y, tp[rp].dist + 10, DIR::W, rp, x1, y1);
        if (can_move(md, x, y, x - 1, y - 1))
            e += add_path(heap, tp, x - 1, y - 1, tp[rp].dist + 14, DIR::NW, rp, x1, y1);
        if (can_move(md, x, y, x, y - 1))
            e += add_path(heap, tp, x, y - 1, tp[rp].dist + 10, DIR::N, rp, x1, y1);
        tp[rp].flag = 1;
        if (e || heap[0] >= MAX_HEAP - 5)
            return -1;
    }
}
Exemple #19
0
/* Process party invitation from sd to account_id. */
int party_invite(dumb_ptr<map_session_data> sd, AccountId account_id)
{
    dumb_ptr<map_session_data> tsd = map_id2sd(account_to_block(account_id));
    PartyPair p = party_search(sd->status.party_id);
    int i;
    int full = 1; /* Indicates whether or not there's room for one more. */

    nullpo_retz(sd);

    if (!tsd || !p || !tsd->sess)
        return 0;

    if (!battle_config.invite_request_check)
    {
        /* Disallow the invitation under these conditions. */
        if (tsd->trade_partner || tsd->npc_id
            || tsd->npc_shopid || pc_checkskill(tsd, SkillID::NV_PARTY) < 1)
        {
            clif_party_inviteack(sd, tsd->status_key.name, 1);
            return 0;
        }
    }

    /* The target player is already in a party, or has a pending invitation. */
    if (tsd->status.party_id || tsd->party_invite)
    {
        clif_party_inviteack(sd, tsd->status_key.name, 0);
        return 0;
    }

    for (i = 0; i < MAX_PARTY; i++)
    {
        /*
         * A character from the target account is already in the same party.
         * The response isn't strictly accurate, as they're separate
         * characters, but we're making do with what was already in place and
         * leaving this (mostly) alone for now.
         */
        if (p->member[i].account_id == account_id)
        {
            clif_party_inviteack(sd, tsd->status_key.name, 1);
            return 0;
        }

        if (!p->member[i].account_id)
            full = 0;
    }

    /* There isn't enough room for a new member. */
    if (full)
    {
        clif_party_inviteack(sd, tsd->status_key.name, 3);
        return 0;
    }

    /* Otherwise, relay the invitation to the target player. */
    tsd->party_invite = sd->status.party_id;
    tsd->party_invite_account = sd->status_key.account_id;

    clif_party_invite(sd, tsd);
    return 0;
}