Commit c4208efd authored by VanillaSalt's avatar VanillaSalt

extra link

parent 1d378cf9
...@@ -1165,6 +1165,136 @@ void card::get_linked_cards(card_set* cset) { ...@@ -1165,6 +1165,136 @@ void card::get_linked_cards(card_set* cset) {
icheck <<= 1; icheck <<= 1;
} }
} }
uint32 card::get_mutual_linked_zone() {
if(!(data.type & TYPE_LINK) || current.location != LOCATION_MZONE)
return 0;
int32 zones = 0;
int32 p = current.controler;
int32 s = current.sequence;
if(s > 0 && s <= 4 && is_link_marker(LINK_MARKER_LEFT)) {
card* pcard = pduel->game_field->player[p].list_mzone[s - 1];
if(pcard && pcard->is_link_marker(LINK_MARKER_RIGHT))
zones |= 1u << (s - 1);
}
if(s <= 3 && is_link_marker(LINK_MARKER_RIGHT)) {
card* pcard = pduel->game_field->player[p].list_mzone[s + 1];
if(pcard && pcard->is_link_marker(LINK_MARKER_LEFT))
zones |= 1u << (s + 1);
}
if(s == 0 && is_link_marker(LINK_MARKER_TOP_RIGHT)) {
card* pcard = pduel->game_field->player[p].list_mzone[5];
if(pcard && pcard->is_link_marker(LINK_MARKER_BOTTOM_LEFT))
zones |= 1u << 5;
pcard = pduel->game_field->player[1 - p].list_mzone[6];
if(pcard && pcard->is_link_marker(LINK_MARKER_TOP_RIGHT))
zones |= 1u << (16 + 6);
}
if(s == 1 && is_link_marker(LINK_MARKER_TOP)) {
card* pcard = pduel->game_field->player[p].list_mzone[5];
if(pcard && pcard->is_link_marker(LINK_MARKER_BOTTOM))
zones |= 1u << 5;
pcard = pduel->game_field->player[1 - p].list_mzone[6];
if(pcard && pcard->is_link_marker(LINK_MARKER_TOP))
zones |= 1u << (16 + 6);
}
if(s == 2 && is_link_marker(LINK_MARKER_TOP_LEFT)) {
card* pcard = pduel->game_field->player[p].list_mzone[5];
if(pcard && pcard->is_link_marker(LINK_MARKER_BOTTOM_RIGHT))
zones |= 1u << 5;
pcard = pduel->game_field->player[1 - p].list_mzone[6];
if(pcard && pcard->is_link_marker(LINK_MARKER_TOP_LEFT))
zones |= 1u << (16 + 6);
}
if(s == 2 && is_link_marker(LINK_MARKER_TOP_RIGHT)) {
card* pcard = pduel->game_field->player[p].list_mzone[6];
if(pcard && pcard->is_link_marker(LINK_MARKER_BOTTOM_LEFT))
zones |= 1u << 6;
pcard = pduel->game_field->player[1 - p].list_mzone[5];
if(pcard && pcard->is_link_marker(LINK_MARKER_TOP_RIGHT))
zones |= 1u << (16 + 5);
}
if(s == 3 && is_link_marker(LINK_MARKER_TOP)) {
card* pcard = pduel->game_field->player[p].list_mzone[6];
if(pcard && pcard->is_link_marker(LINK_MARKER_BOTTOM))
zones |= 1u << 6;
pcard = pduel->game_field->player[1 - p].list_mzone[5];
if(pcard && pcard->is_link_marker(LINK_MARKER_TOP))
zones |= 1u << (16 + 5);
}
if(s == 4 && is_link_marker(LINK_MARKER_TOP_LEFT)) {
card* pcard = pduel->game_field->player[p].list_mzone[6];
if(pcard && pcard->is_link_marker(LINK_MARKER_BOTTOM_RIGHT))
zones |= 1u << 6;
pcard = pduel->game_field->player[1 - p].list_mzone[5];
if(pcard && pcard->is_link_marker(LINK_MARKER_TOP_LEFT))
zones |= 1u << (16 + 5);
}
if(s == 5) {
if(is_link_marker(LINK_MARKER_BOTTOM_LEFT)) {
card* pcard = pduel->game_field->player[p].list_mzone[0];
if(pcard && pcard->is_link_marker(LINK_MARKER_TOP_RIGHT))
zones |= 1u << 0;
}
if(is_link_marker(LINK_MARKER_BOTTOM)) {
card* pcard = pduel->game_field->player[p].list_mzone[1];
if(pcard && pcard->is_link_marker(LINK_MARKER_TOP))
zones |= 1u << 1;
}
if(is_link_marker(LINK_MARKER_BOTTOM_RIGHT)) {
card* pcard = pduel->game_field->player[p].list_mzone[2];
if(pcard && pcard->is_link_marker(LINK_MARKER_TOP_LEFT))
zones |= 1u << 2;
}
if(is_link_marker(LINK_MARKER_TOP_LEFT)) {
card* pcard = pduel->game_field->player[1 - p].list_mzone[4];
if(pcard && pcard->is_link_marker(LINK_MARKER_TOP_LEFT))
zones |= 1u << (16 + 4);
}
if(is_link_marker(LINK_MARKER_TOP)) {
card* pcard = pduel->game_field->player[1 - p].list_mzone[3];
if(pcard && pcard->is_link_marker(LINK_MARKER_TOP))
zones |= 1u << (16 + 3);
}
if(is_link_marker(LINK_MARKER_TOP_RIGHT)) {
card* pcard = pduel->game_field->player[1 - p].list_mzone[2];
if(pcard && pcard->is_link_marker(LINK_MARKER_TOP_RIGHT))
zones |= 1u << (16 + 2);
}
}
if(s == 6) {
if(is_link_marker(LINK_MARKER_BOTTOM_LEFT)) {
card* pcard = pduel->game_field->player[p].list_mzone[2];
if(pcard && pcard->is_link_marker(LINK_MARKER_TOP_RIGHT))
zones |= 1u << 2;
}
if(is_link_marker(LINK_MARKER_BOTTOM)) {
card* pcard = pduel->game_field->player[p].list_mzone[3];
if(pcard && pcard->is_link_marker(LINK_MARKER_TOP))
zones |= 1u << 3;
}
if(is_link_marker(LINK_MARKER_BOTTOM_RIGHT)) {
card* pcard = pduel->game_field->player[p].list_mzone[4];
if(pcard && pcard->is_link_marker(LINK_MARKER_TOP_LEFT))
zones |= 1u << 4;
}
if(is_link_marker(LINK_MARKER_TOP_LEFT)) {
card* pcard = pduel->game_field->player[1 - p].list_mzone[2];
if(pcard && pcard->is_link_marker(LINK_MARKER_TOP_LEFT))
zones |= 1u << (16 + 2);
}
if(is_link_marker(LINK_MARKER_TOP)) {
card* pcard = pduel->game_field->player[1 - p].list_mzone[1];
if(pcard && pcard->is_link_marker(LINK_MARKER_TOP))
zones |= 1u << (16 + 1);
}
if(is_link_marker(LINK_MARKER_TOP_RIGHT)) {
card* pcard = pduel->game_field->player[1 - p].list_mzone[0];
if(pcard && pcard->is_link_marker(LINK_MARKER_TOP_RIGHT))
zones |= 1u << (16 + 0);
}
}
return zones;
}
int32 card::is_position(int32 pos) { int32 card::is_position(int32 pos) {
return current.position & pos; return current.position & pos;
} }
...@@ -2729,12 +2859,7 @@ int32 card::is_can_be_special_summoned(effect* reason_effect, uint32 sumtype, ui ...@@ -2729,12 +2859,7 @@ int32 card::is_can_be_special_summoned(effect* reason_effect, uint32 sumtype, ui
if(is_status(STATUS_FORBIDDEN)) if(is_status(STATUS_FORBIDDEN))
return FALSE; return FALSE;
if(zone != 0xff) { if(zone != 0xff) {
int32 ct; if(pduel->game_field->get_useable_count(this, toplayer, LOCATION_MZONE, sumplayer, LOCATION_REASON_TOFIELD, zone) <= 0)
if(pduel->game_field->core.duel_rule >= 4 && current.location == LOCATION_EXTRA)
ct = pduel->game_field->get_useable_count_fromex(toplayer, sumplayer, zone);
else
ct = pduel->game_field->get_useable_count(toplayer, LOCATION_MZONE, sumplayer, LOCATION_REASON_TOFIELD, zone);
if(ct <= 0)
return FALSE; return FALSE;
} }
pduel->game_field->save_lp_cost(); pduel->game_field->save_lp_cost();
......
...@@ -195,6 +195,7 @@ public: ...@@ -195,6 +195,7 @@ public:
int32 is_link_marker(uint32 dir); int32 is_link_marker(uint32 dir);
uint32 get_linked_zone(); uint32 get_linked_zone();
void get_linked_cards(card_set* cset); void get_linked_cards(card_set* cset);
uint32 get_mutual_linked_zone();
int32 is_position(int32 pos); int32 is_position(int32 pos);
void set_status(uint32 status, int32 enabled); void set_status(uint32 status, int32 enabled);
int32 get_status(uint32 status); int32 get_status(uint32 status);
......
...@@ -485,15 +485,29 @@ int32 field::is_location_useable(uint8 playerid, uint8 location, uint8 sequence) ...@@ -485,15 +485,29 @@ int32 field::is_location_useable(uint8 playerid, uint8 location, uint8 sequence)
if (location != LOCATION_MZONE && location != LOCATION_SZONE) if (location != LOCATION_MZONE && location != LOCATION_SZONE)
return TRUE; return TRUE;
uint32 flag = player[playerid].disabled_location | player[playerid].used_location; uint32 flag = player[playerid].disabled_location | player[playerid].used_location;
if (location == LOCATION_MZONE && flag & (0x1u << sequence)) if (location == LOCATION_MZONE) {
return FALSE; if(flag & (0x1u << sequence))
if (location == LOCATION_SZONE && flag & (0x100u << sequence)) return FALSE;
return FALSE; if(sequence >= 5) {
uint32 oppo = player[1 - playerid].disabled_location | player[1 - playerid].used_location;
if(oppo & (0x1u << (11 - sequence)))
return FALSE;
}
} else {
if(flag & (0x100u << sequence))
return FALSE;
}
return TRUE; return TRUE;
} }
// uplayer: request player, PLAYER_NONE means ignoring EFFECT_MAX_MZONE, EFFECT_MAX_SZONE // uplayer: request player, PLAYER_NONE means ignoring EFFECT_MAX_MZONE, EFFECT_MAX_SZONE
// list: store local flag in list // list: store local flag in list
// return: usable count of LOCATION_MZONE or real LOCATION_SZONE of plaerid requested by uplayer (may be negative) // return: usable count of LOCATION_MZONE or real LOCATION_SZONE of playerid requested by uplayer (may be negative)
int32 field::get_useable_count(card* pcard, uint8 playerid, uint8 location, uint8 uplayer, uint32 reason, uint32 zone, uint32* list) {
if(core.duel_rule >= 4 && location == LOCATION_MZONE && pcard->current.location == LOCATION_EXTRA)
return get_useable_count_fromex(pcard, playerid, uplayer, zone, list);
else
return get_useable_count(playerid, location, uplayer, reason, zone, list);
}
int32 field::get_useable_count(uint8 playerid, uint8 location, uint8 uplayer, uint32 reason, uint32 zone, uint32* list) { int32 field::get_useable_count(uint8 playerid, uint8 location, uint8 uplayer, uint32 reason, uint32 zone, uint32* list) {
if (location != LOCATION_MZONE && location != LOCATION_SZONE) if (location != LOCATION_MZONE && location != LOCATION_SZONE)
return 0; return 0;
...@@ -530,7 +544,7 @@ int32 field::get_useable_count(uint8 playerid, uint8 location, uint8 uplayer, ui ...@@ -530,7 +544,7 @@ int32 field::get_useable_count(uint8 playerid, uint8 location, uint8 uplayer, ui
return count; return count;
} }
} }
int32 field::get_useable_count_fromex(uint8 playerid, uint8 uplayer, uint32 zone, uint32* list) { int32 field::get_useable_count_fromex(card* pcard, uint8 playerid, uint8 uplayer, uint32 zone, uint32* list) {
uint32 flag = player[playerid].disabled_location | player[playerid].used_location; uint32 flag = player[playerid].disabled_location | player[playerid].used_location;
uint32 used_flag = player[playerid].used_location; uint32 used_flag = player[playerid].used_location;
uint32 linked_zone = get_linked_zone(playerid); uint32 linked_zone = get_linked_zone(playerid);
...@@ -538,7 +552,13 @@ int32 field::get_useable_count_fromex(uint8 playerid, uint8 uplayer, uint32 zone ...@@ -538,7 +552,13 @@ int32 field::get_useable_count_fromex(uint8 playerid, uint8 uplayer, uint32 zone
used_flag = used_flag & 0x1f; used_flag = used_flag & 0x1f;
int32 used_count = field_used_count[flag]; int32 used_count = field_used_count[flag];
int32 maxcount = 6; int32 maxcount = 6;
if(player[playerid].list_mzone[5] || player[playerid].list_mzone[6] || !(zone & ((1u << 5) | (1u << 6)))) { if(player[playerid].list_mzone[5] && is_location_useable(playerid, LOCATION_MZONE, 6)
&& (zone & (1u << 6)) && check_extra_link(playerid, pcard, 6)) {
flag |= 1u << 6;
} else if(player[playerid].list_mzone[6] && is_location_useable(playerid, LOCATION_MZONE, 5)
&& (zone & (1u << 5)) && check_extra_link(playerid, pcard, 5)) {
flag |= 1u << 5;
} else if(player[playerid].list_mzone[5] || player[playerid].list_mzone[6] || !(zone & ((1u << 5) | (1u << 6)))) {
flag |= (1u << 5) | (1u << 6); flag |= (1u << 5) | (1u << 6);
maxcount = 5; maxcount = 5;
} else if(player[1 - playerid].list_mzone[5] || !is_location_useable(playerid, LOCATION_MZONE, 6) || !(zone & (1u << 6))) } else if(player[1 - playerid].list_mzone[5] || !is_location_useable(playerid, LOCATION_MZONE, 6) || !(zone & (1u << 6)))
...@@ -611,6 +631,61 @@ uint32 field::get_linked_zone(int32 playerid) { ...@@ -611,6 +631,61 @@ uint32 field::get_linked_zone(int32 playerid) {
} }
return zones; return zones;
} }
int32 field::check_extra_link(int32 playerid) {
if(!player[playerid].list_mzone[5] || !player[playerid].list_mzone[6])
return FALSE;
card* pcard = player[playerid].list_mzone[5];
uint32 checked = 1u << 5;
uint32 linked_zone = pcard->get_mutual_linked_zone();
while(true) {
if((linked_zone >> 6) & 1)
return TRUE;
int32 checking = (int32)(linked_zone & ~checked);
if(!checking)
return FALSE;
int32 rightmost = checking & (-checking);
checked |= (uint32)rightmost;
if(rightmost < 0x10000) {
for(int32 i = 0; i < 7; ++i) {
if(rightmost & 1) {
pcard = player[playerid].list_mzone[i];
linked_zone |= pcard->get_mutual_linked_zone();
break;
}
rightmost >>= 1;
}
} else {
rightmost >>= 16;
for(int32 i = 0; i < 7; ++i) {
if(rightmost & 1) {
pcard = player[1 - playerid].list_mzone[i];
uint32 zone = pcard->get_mutual_linked_zone();
linked_zone |= (zone << 16) | (zone >> 16);
break;
}
rightmost >>= 1;
}
}
}
return FALSE;
}
int32 field::check_extra_link(int32 playerid, card* pcard, int32 sequence) {
if(player[playerid].list_mzone[sequence])
return FALSE;
uint8 cur_controler = pcard->current.controler;
uint8 cur_location = pcard->current.location;
uint8 cur_sequence = pcard->current.sequence;
player[playerid].list_mzone[sequence] = pcard;
pcard->current.controler = playerid;
pcard->current.location = LOCATION_MZONE;
pcard->current.sequence = sequence;
int32 ret = check_extra_link(playerid);
player[playerid].list_mzone[sequence] = 0;
pcard->current.controler = cur_controler;
pcard->current.location = cur_location;
pcard->current.sequence = cur_sequence;
return ret;
}
void field::shuffle(uint8 playerid, uint8 location) { void field::shuffle(uint8 playerid, uint8 location) {
if(!(location & (LOCATION_HAND | LOCATION_DECK))) if(!(location & (LOCATION_HAND | LOCATION_DECK)))
return; return;
......
...@@ -341,9 +341,12 @@ public: ...@@ -341,9 +341,12 @@ public:
void set_control(card* pcard, uint8 playerid, uint16 reset_phase, uint8 reset_count); void set_control(card* pcard, uint8 playerid, uint16 reset_phase, uint8 reset_count);
card* get_field_card(uint8 playerid, uint8 location, uint8 sequence); card* get_field_card(uint8 playerid, uint8 location, uint8 sequence);
int32 is_location_useable(uint8 playerid, uint8 location, uint8 sequence); int32 is_location_useable(uint8 playerid, uint8 location, uint8 sequence);
int32 get_useable_count(card* pcard, uint8 playerid, uint8 location, uint8 uplayer, uint32 reason, uint32 zone = 0xff, uint32* list = 0);
int32 get_useable_count(uint8 playerid, uint8 location, uint8 uplayer, uint32 reason, uint32 zone = 0xff, uint32* list = 0); int32 get_useable_count(uint8 playerid, uint8 location, uint8 uplayer, uint32 reason, uint32 zone = 0xff, uint32* list = 0);
int32 get_useable_count_fromex(uint8 playerid, uint8 uplayer, uint32 zone = 0xff, uint32* list = 0); int32 get_useable_count_fromex(card* pcard, uint8 playerid, uint8 uplayer, uint32 zone = 0xff, uint32* list = 0);
uint32 get_linked_zone(int32 playerid); uint32 get_linked_zone(int32 playerid);
int32 check_extra_link(int32 playerid);
int32 check_extra_link(int32 playerid, card* pcard, int32 sequence);
void shuffle(uint8 playerid, uint8 location); void shuffle(uint8 playerid, uint8 location);
void reset_sequence(uint8 playerid, uint8 location); void reset_sequence(uint8 playerid, uint8 location);
void swap_deck_and_grave(uint8 playerid); void swap_deck_and_grave(uint8 playerid);
......
...@@ -2568,12 +2568,7 @@ int32 field::special_summon_step(uint16 step, group* targets, card* target, uint ...@@ -2568,12 +2568,7 @@ int32 field::special_summon_step(uint16 step, group* targets, card* target, uint
core.units.begin()->step = 4; core.units.begin()->step = 4;
return FALSE; return FALSE;
} }
int32 ct; if(get_useable_count(target, playerid, LOCATION_MZONE, target->summon_player, LOCATION_REASON_TOFIELD, zone) <= 0) {
if(core.duel_rule >= 4 && target->current.location == LOCATION_EXTRA)
ct = get_useable_count_fromex(playerid, target->summon_player, zone);
else
ct = get_useable_count(playerid, LOCATION_MZONE, target->summon_player, LOCATION_REASON_TOFIELD, zone);
if(ct <= 0) {
if(target->current.location != LOCATION_GRAVE) if(target->current.location != LOCATION_GRAVE)
core.ss_tograve_set.insert(target); core.ss_tograve_set.insert(target);
core.units.begin()->step = 4; core.units.begin()->step = 4;
...@@ -3866,7 +3861,7 @@ int32 field::move_to_field(uint16 step, card* target, uint32 enable, uint32 ret, ...@@ -3866,7 +3861,7 @@ int32 field::move_to_field(uint16 step, card* target, uint32 enable, uint32 ret,
add_process(PROCESSOR_SELECT_PLACE, 0, 0, 0, move_player, flag, 1); add_process(PROCESSOR_SELECT_PLACE, 0, 0, 0, move_player, flag, 1);
} else if(core.duel_rule >= 4 && location == LOCATION_MZONE && target->current.location == LOCATION_EXTRA) { } else if(core.duel_rule >= 4 && location == LOCATION_MZONE && target->current.location == LOCATION_EXTRA) {
uint32 flag; uint32 flag;
int32 ct = get_useable_count_fromex(playerid, move_player, zone, &flag); int32 ct = get_useable_count_fromex(target, playerid, move_player, zone, &flag);
if((ret == 1) && (ct <= 0 || target->is_status(STATUS_FORBIDDEN) || check_unique_onfield(target, playerid, location))) { if((ret == 1) && (ct <= 0 || target->is_status(STATUS_FORBIDDEN) || check_unique_onfield(target, playerid, location))) {
core.units.begin()->step = 3; core.units.begin()->step = 3;
send_to(target, core.reason_effect, REASON_RULE, core.reason_player, PLAYER_NONE, LOCATION_GRAVE, 0, 0); send_to(target, core.reason_effect, REASON_RULE, core.reason_player, PLAYER_NONE, LOCATION_GRAVE, 0, 0);
......
...@@ -4849,8 +4849,8 @@ void field::refresh_location_info_instant() { ...@@ -4849,8 +4849,8 @@ void field::refresh_location_info_instant() {
value = eset[i]->get_value(); value = eset[i]->get_value();
player[p].disabled_location |= (value >> 8) & 0x1f00; player[p].disabled_location |= (value >> 8) & 0x1f00;
} }
player[0].disabled_location |= ((player[1].disabled_location >> 5) << 6) | ((player[1].disabled_location >> 6) << 5); player[0].disabled_location |= (((player[1].disabled_location >> 5) & 1) << 6) | (((player[1].disabled_location >> 6) & 1) << 5);
player[1].disabled_location |= ((player[0].disabled_location >> 5) << 6) | ((player[0].disabled_location >> 6) << 5); player[1].disabled_location |= (((player[0].disabled_location >> 5) & 1) << 6) | (((player[0].disabled_location >> 6) & 1) << 5);
uint32 dis2 = player[0].disabled_location | (player[1].disabled_location << 16); uint32 dis2 = player[0].disabled_location | (player[1].disabled_location << 16);
if(dis1 != dis2) { if(dis1 != dis2) {
pduel->write_buffer8(MSG_FIELD_DISABLED); pduel->write_buffer8(MSG_FIELD_DISABLED);
...@@ -5018,8 +5018,8 @@ int32 field::refresh_location_info(uint16 step) { ...@@ -5018,8 +5018,8 @@ int32 field::refresh_location_info(uint16 step) {
return FALSE; return FALSE;
} }
case 7: { case 7: {
player[0].disabled_location |= ((player[1].disabled_location >> 5) << 6) | ((player[1].disabled_location >> 6) << 5); player[0].disabled_location |= (((player[1].disabled_location >> 5) & 1) << 6) | (((player[1].disabled_location >> 6) & 1) << 5);
player[1].disabled_location |= ((player[0].disabled_location >> 5) << 6) | ((player[0].disabled_location >> 6) << 5); player[1].disabled_location |= (((player[0].disabled_location >> 5) & 1) << 6) | (((player[0].disabled_location >> 6) & 1) << 5);
uint32 dis = player[0].disabled_location | (player[1].disabled_location << 16); uint32 dis = player[0].disabled_location | (player[1].disabled_location << 16);
if(dis != (uint32)core.units.begin()->arg2) { if(dis != (uint32)core.units.begin()->arg2) {
pduel->write_buffer8(MSG_FIELD_DISABLED); pduel->write_buffer8(MSG_FIELD_DISABLED);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment