예제 #1
0
def yesno(self, player, desc):
    pl = self.players[player]
    old_parser = pl.connection.parser

    def r(caller):
        if caller.text.lower().startswith('y'):
            self.set_responsei(1)
            reactor.callLater(0, process_duel, self)
        elif caller.text.lower().startswith('n'):
            self.set_responsei(0)
            reactor.callLater(0, process_duel, self)
        else:
            pl.notify(opt)
            pl.notify(DuelReader, r, restore_parser=old_parser)

    if desc > 10000:
        code = desc >> 4
        card = Card(code)
        opt = card.get_strings(pl)[desc & 0xF]
        if opt == "":
            opt = pl._("Unknown question from %s. Yes or no?") % (
                card.get_name(pl))
    else:
        opt = "String %d" % desc
        opt = pl.strings["system"].get(desc, opt)
    pl.notify(opt)
    pl.notify(DuelReader, r, restore_parser=old_parser)
예제 #2
0
def msg_summoning(self, data, special=False):
    data = io.BytesIO(data[1:])
    code = self.read_u32(data)
    card = Card(code)
    card.set_location(self.read_u32(data))
    self.cm.call_callbacks('summoning', card, special=special)
    return data.read()
예제 #3
0
파일: set.py 프로젝트: yncat/yugioh-game
def msg_set(self, data):
    data = io.BytesIO(data[1:])
    code = self.read_u32(data)
    loc = self.read_u32(data)
    card = Card(code)
    card.set_location(loc)
    self.cm.call_callbacks('set', card)
    return data.read()
예제 #4
0
def msg_select_effectyn(self, data):
    data = io.BytesIO(data[1:])
    player = self.read_u8(data)
    card = Card(self.read_u32(data))
    card.set_location(self.read_u32(data))
    desc = self.read_u32(data)
    self.cm.call_callbacks("select_effectyn", player, card, desc)
    return data.read()
예제 #5
0
def msg_chaining(self, data):
    data = io.BytesIO(data[1:])
    code = self.read_u32(data)
    card = Card(code)
    card.set_location(self.read_u32(data))
    tc = self.read_u8(data)
    tl = self.read_u8(data)
    ts = self.read_u8(data)
    desc = self.read_u32(data)
    cs = self.read_u8(data)
    self.cm.call_callbacks('chaining', card, tc, tl, ts, desc, cs)
    return data.read()
예제 #6
0
def msg_sort_card(self, data):
    data = io.BytesIO(data[1:])
    player = self.read_u8(data)
    size = self.read_u8(data)
    cards = []
    for i in range(size):
        card = Card(self.read_u32(data))
        card.controller = self.read_u8(data)
        card.location = self.read_u8(data)
        card.sequence = self.read_u8(data)
        cards.append(card)
    self.cm.call_callbacks('sort_card', player, cards)
    return data.read()
예제 #7
0
def select_option(self, player, options):
    pl = self.players[player]

    def r(caller):
        idx = int(caller.text)
        opt = options[idx]

        for p in self.players + self.watchers:

            if opt > 10000:
                string = card.get_strings(p)[opt & 0xF]
            else:
                string = p._("Unknown option %d" % opt)
                string = p.strings["system"].get(opt, string)

            if p is pl:
                p.notify(
                    p._("You selected option {0}: {1}").format(
                        idx + 1, string))
            else:
                p.notify(
                    p._("{0} selected option {1}: {2}").format(
                        pl.nickname, idx + 1, string))

        self.set_responsei(idx)
        reactor.callLater(0, process_duel, self)

    card = None
    opts = []
    for opt in options:
        if opt > 10000:
            code = opt >> 4
            card = Card(code)
            string = card.get_strings(pl)[opt & 0xF]
        else:
            string = pl._("Unknown option %d" % opt)
            string = pl.strings["system"].get(opt, string)
        opts.append(string)
    pl.notify(
        pl._("Select option:"),
        no_abort=pl._("Invalid option."),
        prompt=pl._("Select option:"),
        persistent=True,
        restore_parser=DuelParser,
    )
    for idx, opt in enumerate(opts):
        pl.notify(str(idx) + ": " + str(opt))
    pl.notify(DuelReader,
              r,
              no_abort=pl._("Invalid command"),
              restore_parser=DuelParser)
예제 #8
0
def msg_select_unselect_card(self, data):
    data = io.BytesIO(data[1:])
    player = self.read_u8(data)
    finishable = self.read_u8(data)
    cancelable = self.read_u8(data)
    min = self.read_u8(data)
    max = self.read_u8(data)
    select_size = self.read_u8(data)
    select_cards = []
    for i in range(select_size):
        code = self.read_u32(data)
        loc = self.read_u32(data)
        card = Card(code)
        card.set_location(loc)
        select_cards.append(card)
    unselect_size = self.read_u8(data)
    unselect_cards = []
    for i in range(unselect_size):
        code = self.read_u32(data)
        loc = self.read_u32(data)
        card = Card(code)
        card.set_location(loc)
        unselect_cards.append(card)
    self.cm.call_callbacks('select_unselect_card', player, finishable,
                           cancelable, min, max, select_cards, unselect_cards)
    return data.read()
예제 #9
0
def msg_select_position(self, data):
    data = io.BytesIO(data[1:])
    player = self.read_u8(data)
    code = self.read_u32(data)
    card = Card(code)
    positions = POSITION(self.read_u8(data))
    self.cm.call_callbacks("select_position", player, card, positions)
    return data.read()
예제 #10
0
def msg_confirm_decktop(self, data):
    cards = []
    data = io.BytesIO(data[1:])
    player = self.read_u8(data)
    count = self.read_u8(data)
    for i in range(count):
        code = self.read_u32(data)
        if code & 0x80000000:
            code = code ^ 0x80000000  # don't know what this actually does
        card = Card(code)
        card.controller = self.read_u8(data)
        card.location = LOCATION(self.read_u8(data))
        card.sequence = self.read_u8(data)
        cards.append(card)

    self.cm.call_callbacks('confirm_decktop', player, cards)
    return data.read()
예제 #11
0
def msg_decktop(self, data):
    data = io.BytesIO(data[1:])
    player = self.read_u8(data)
    self.read_u8(data)  # don't know what this number does
    code = self.read_u32(data)
    if code & 0x80000000:
        code = code ^ 0x80000000  # don't know what this actually does
    self.cm.call_callbacks('decktop', player, Card(code))
    return data.read()
예제 #12
0
파일: draw.py 프로젝트: yncat/yugioh-game
def msg_draw(self, data):
	data = io.BytesIO(data[1:])
	player = self.read_u8(data)
	drawed = self.read_u8(data)
	cards = []
	for i in range(drawed):
		c = self.read_u32(data)
		card = Card(c & 0x7fffffff)
		cards.append(card)
	self.cm.call_callbacks('draw', player, cards)
	return data.read()
def msg_select_chain(self, data):
    data = io.BytesIO(data[1:])
    player = self.read_u8(data)
    size = self.read_u8(data)
    spe_count = self.read_u8(data)
    forced = self.read_u8(data)
    hint_timing = self.read_u32(data)
    other_timing = self.read_u32(data)
    chains = []
    for i in range(size):
        et = self.read_u8(data)
        code = self.read_u32(data)
        loc = self.read_u32(data)
        card = Card(code)
        card.set_location(loc)
        desc = self.read_u32(data)
        chains.append((et, card, desc))
    self.cm.call_callbacks('select_chain', player, size, spe_count, forced,
                           chains)
    return data.read()
예제 #14
0
def msg_swap(self, data):
    data = io.BytesIO(data[1:])

    code1 = self.read_u32(data)
    location1 = self.read_u32(data)
    code2 = self.read_u32(data)
    location2 = self.read_u32(data)

    card1 = Card(code1)
    card1.set_location(location1)
    card2 = Card(code2)
    card2.set_location(location2)
    self.cm.call_callbacks('swap', card1, card2)

    return data.read()
예제 #15
0
def yesno(self, player, desc):
    pl = self.players[player]
    old_parser = pl.connection.parser

    def yes(caller):
        self.set_responsei(1)
        reactor.callLater(0, process_duel, self)

    def no(caller):
        self.set_responsei(0)
        reactor.callLater(0, process_duel, self)

    if desc > 10000:
        code = desc >> 4
        card = Card(code)
        opt = card.get_strings(pl)[desc & 0xf]
        if opt == '':
            opt = pl._('Unknown question from %s. Yes or no?') % (
                card.get_name(pl))
    else:
        opt = "String %d" % desc
        opt = pl.strings['system'].get(desc, opt)
    pl.notify(yes_or_no_parser, opt, yes, no=no, restore_parser=old_parser)
예제 #16
0
def yesno(self, player, desc):
	pl = self.players[player]
	old_parser = pl.connection.parser
	def yes(caller):
		self.set_responsei(1)
		reactor.callLater(0, process_duel, self)
	def no(caller):
		self.set_responsei(0)
		reactor.callLater(0, process_duel, self)
	if desc > 10000:
		code = desc >> 4
		opt = Card(code).get_strings(pl)[desc & 0xf]
	else:
		opt = "String %d" % desc
		opt = globals.strings[pl.language]['system'].get(desc, opt)
	pl.notify(yes_or_no_parser, opt, yes, no=no, restore_parser=old_parser)
예제 #17
0
def msg_pos_change(self, data):
	data = io.BytesIO(data[1:])
	code = self.read_u32(data)
	card = Card(code)
	card.controller = self.read_u8(data)
	card.location = LOCATION(self.read_u8(data))
	card.sequence = self.read_u8(data)
	prevpos = POSITION(self.read_u8(data))
	card.position = POSITION(self.read_u8(data))
	self.cm.call_callbacks('pos_change', card, prevpos)
	return data.read()
예제 #18
0
def msg_tag_swap(self, data):
    data = io.BytesIO(data[1:])
    player = self.read_u8(data)
    main_deck_count = self.read_u8(data)
    extra_deck_count = self.read_u8(data)
    extra_p_count = self.read_u8(data)
    hand_count = self.read_u8(data)
    top_card = self.read_u32(data)
    # we don't need the following information, so we trash it
    # that allows us to process all following messages too (if any)
    for i in range(hand_count):
        self.read_u32(data)
    for i in range(extra_deck_count):
        self.read_u32(data)
    self.cm.call_callbacks('tag_swap', player)
    if top_card > 0:
        self.cm.call_callbacks('decktop', player, Card(top_card))
    return data.read()
예제 #19
0
def msg_select_tribute(self, data):
	data = io.BytesIO(data[1:])
	player = self.read_u8(data)
	cancelable = self.read_u8(data)
	min = self.read_u8(data)
	max = self.read_u8(data)
	size = self.read_u8(data)
	cards = []
	for i in range(size):
		code = self.read_u32(data)
		card = Card(code)
		card.controller = self.read_u8(data)
		card.location = LOCATION(self.read_u8(data))
		card.sequence = self.read_u8(data)
		card.position = self.get_card(card.controller, card.location, card.sequence).position
		card.release_param = self.read_u8(data)
		cards.append(card)
	self.cm.call_callbacks('select_tribute', player, cancelable, min, max, cards)
	return data.read()
예제 #20
0
def msg_select_counter(self, data):
    data = io.BytesIO(data[1:])
    player = self.read_u8(data)
    countertype = self.read_u16(data)
    count = self.read_u16(data)
    size = self.read_u8(data)
    cards = []
    for i in range(size):
        card = Card(self.read_u32(data))
        card.controller = self.read_u8(data)
        card.location = LOCATION(self.read_u8(data))
        card.sequence = self.read_u8(data)
        card.counter = self.read_u16(data)
        cards.append(card)
    self.cm.call_callbacks('select_counter', player, countertype, count, cards)
    return data.read()
예제 #21
0
def select_option(self, player, options):
    pl = self.players[player]

    def select(caller, idx):
        self.set_responsei(idx)
        reactor.callLater(0, process_duel, self)

    opts = []
    for opt in options:
        if opt > 10000:
            code = opt >> 4
            string = Card(code).get_strings(pl)[opt & 0xf]
        else:
            string = "Unknown option %d" % opt
            string = globals.strings[pl.language]['system'].get(opt, string)
        opts.append(string)
    m = Menu(pl._("Select option:"),
             no_abort=pl._("Invalid option."),
             persistent=True,
             prompt=pl._("Select option:"),
             restore_parser=DuelParser)
    for idx, opt in enumerate(opts):
        m.item(opt)(lambda caller, idx=idx: select(caller, idx))
    pl.notify(m)
예제 #22
0
def move(self, code, location, newloc, reason):
	card = Card(code)
	card.set_location(location)
	pl = self.players[card.controller]
	op = self.players[1 - card.controller]
	plspec = card.get_spec(pl.duel_player)
	ploc = (location >> 8) & 0xff
	pnewloc = (newloc >> 8) & 0xff
	if reason & 0x01 and ploc != pnewloc:
		pl.notify(pl._("Card %s (%s) destroyed.") % (plspec, card.get_name(pl)))
		for w in self.watchers+[op]:
			s = card.get_spec(w.duel_player)
			w.notify(w._("Card %s (%s) destroyed.") % (s, card.get_name(w)))
	elif ploc == pnewloc and ploc in (LOCATION_MZONE, LOCATION_SZONE):
		cnew = Card(code)
		cnew.set_location(newloc)

		if (location & 0xff) != (newloc & 0xff):
			# controller changed too (e.g. change of heart)
			pl.notify(pl._("your card {spec} ({name}) changed controller to {op} and is now located at {targetspec}.").format(spec=plspec, name = card.get_name(pl), op = op.nickname, targetspec = cnew.get_spec(pl.duel_player)))
			op.notify(op._("you now control {plname}s card {spec} ({name}) and its located at {targetspec}.").format(plname=pl.nickname, spec=card.get_spec(op.duel_player), name = card.get_name(op), targetspec = cnew.get_spec(op.duel_player)))
			for w in self.watchers:
				s = card.get_spec(w.duel_player)
				ts = cnew.get_spec(w.duel_player)
				w.notify(w._("{plname}s card {spec} ({name}) changed controller to {op} and is now located at {targetspec}.").format(plname=pl.nickname, op=op.nickname, spec=s, targetspec=ts, name=card.get_name(w)))
		else:
			# only place changed (alien decks e.g.)
			pl.notify(pl._("your card {spec} ({name}) switched its zone to {targetspec}.").format(spec=plspec, name=card.get_name(pl), targetspec=cnew.get_spec(pl.duel_player)))
			for w in self.watchers+[op]:
				s = card.get_spec(w.duel_player)
				ts = cnew.get_spec(w.duel_player)
				w.notify(w._("{plname}s card {spec} ({name}) changed its zone to {targetspec}.").format(plname=pl.nickname, spec=s, targetspec=ts, name=card.get_name(w)))
	elif reason & 0x4000 and ploc != pnewloc:
		pl.notify(pl._("you discarded {spec} ({name}).").format(spec = plspec, name = card.get_name(pl)))
		for w in self.watchers+[op]:
			s = card.get_spec(w.duel_player)
			w.notify(w._("{plname} discarded {spec} ({name}).").format(plname=pl.nickname, spec=s, name=card.get_name(w)))
	elif ploc == LOCATION_REMOVED and pnewloc in (LOCATION_SZONE, LOCATION_MZONE):
		cnew = Card(code)
		cnew.set_location(newloc)
		pl.notify(pl._("your banished card {spec} ({name}) returns to the field at {targetspec}.").format(spec=plspec, name=card.get_name(pl), targetspec=cnew.get_spec(pl.duel_player)))
		for w in self.watchers+[op]:
			s=card.get_spec(w.duel_player)
			ts = cnew.get_spec(w.duel_player)
			w.notify(w._("{plname}'s banished card {spec} ({name}) returned to their field at {targetspec}.").format(plname=pl.nickname, spec=s, targetspec=ts, name=card.get_name(w)))
	elif ploc == LOCATION_GRAVE and pnewloc in (LOCATION_SZONE, LOCATION_MZONE):
		cnew = Card(code)
		cnew.set_location(newloc)
		pl.notify(pl._("your card {spec} ({name}) returns from the graveyard to the field at {targetspec}.").format(spec=plspec, name=card.get_name(pl), targetspec=cnew.get_spec(pl.duel_player)))
		for w in self.watchers+[op]:
			s = card.get_spec(w.duel_player)
			ts = cnew.get_spec(w.duel_player)
			w.notify(w._("{plname}s card {spec} ({name}) returns from the graveyard to the field at {targetspec}.").format(plname = pl.nickname, spec=s, targetspec=ts, name = card.get_name(w)))
	elif pnewloc == LOCATION_HAND and ploc != pnewloc:
		pl.notify(pl._("Card {spec} ({name}) returned to hand.")
			.format(spec=plspec, name=card.get_name(pl)))
		for w in self.watchers+[op]:
			if card.position in (POS_FACEDOWN_DEFENSE, POS_FACEDOWN):
				name = w._("Face-down card")
			else:
				name = card.get_name(w)
			s = card.get_spec(w.duel_player)
			w.notify(w._("{plname}'s card {spec} ({name}) returned to their hand.")
				.format(plname=pl.nickname, spec=s, name=name))
	elif reason & 0x12 and ploc != pnewloc:
		pl.notify(pl._("You tribute {spec} ({name}).")
			.format(spec=plspec, name=card.get_name(pl)))
		for w in self.watchers+[op]:
			s = card.get_spec(w.duel_player)
			if card.position in (POS_FACEDOWN_DEFENSE, POS_FACEDOWN):
				name = w._("%s card") % card.get_position(w)
			else:
				name = card.get_name(w)
			w.notify(w._("{plname} tributes {spec} ({name}).")
				.format(plname=pl.nickname, spec=s, name=name))
	elif ploc == LOCATION_OVERLAY+LOCATION_MZONE and pnewloc in (LOCATION_GRAVE, LOCATION_REMOVED):
		pl.notify(pl._("you detached %s.")%(card.get_name(pl)))
		for w in self.watchers+[op]:
			w.notify(w._("%s detached %s")%(pl.nickname, card.get_name(w)))
	elif ploc != pnewloc and pnewloc == LOCATION_GRAVE:
		pl.notify(pl._("your card {spec} ({name}) was sent to the graveyard.").format(spec=plspec, name=card.get_name(pl)))
		for w in self.watchers+[op]:
			s = card.get_spec(w.duel_player)
			w.notify(w._("{plname}'s card {spec} ({name}) was sent to the graveyard.").format(plname=pl.nickname, spec=s, name=card.get_name(w)))
	elif ploc != pnewloc and pnewloc == LOCATION_REMOVED:
		pl.notify(pl._("your card {spec} ({name}) was banished.").format(spec=plspec, name=card.get_name(pl)))
		for w in self.watchers+[op]:
			if card.position in (POS_FACEDOWN_DEFENSE, POS_FACEDOWN):
				name = w._("%s card")%(card.get_position(w))
			else:
				name = card.get_name(w)
			s = card.get_spec(w.duel_player)
			w.notify(w._("{plname}'s card {spec} ({name}) was banished.").format(plname=pl.nickname, spec=s, name=name))
	elif ploc != pnewloc and pnewloc == LOCATION_DECK:
		pl.notify(pl._("your card {spec} ({name}) returned to your deck.").format(spec=plspec, name=card.get_name(pl)))
		for w in self.watchers+[op]:
			s = card.get_spec(w.duel_player)
			w.notify(w._("{plname}'s card {spec} ({name}) returned to their deck.").format(plname=pl.nickname, spec=s, name=card.get_name(w)))
	elif ploc != pnewloc and pnewloc == LOCATION_EXTRA:
		pl.notify(pl._("your card {spec} ({name}) returned to your extra deck.").format(spec=plspec, name=card.get_name(pl)))
		for w in self.watchers+[op]:
			s = card.get_spec(w.duel_player)
			w.notify(w._("{plname}'s card {spec} ({name}) returned to their extra deck.").format(plname=pl.nickname, spec=s, name=card.get_name(w)))
예제 #23
0
def msg_select_sum(self, data):
    data = io.BytesIO(data[1:])
    mode = self.read_u8(data)
    player = self.read_u8(data)
    val = self.read_u32(data)
    select_min = self.read_u8(data)
    select_max = self.read_u8(data)
    count = self.read_u8(data)
    must_select = []
    for i in range(count):
        code = self.read_u32(data)
        card = Card(code)
        card.controller = self.read_u8(data)
        card.location = LOCATION(self.read_u8(data))
        card.sequence = self.read_u8(data)
        param = self.read_u32(data)
        card.param = (
            param & 0xff,
            param >> 16,
        )
        must_select.append(card)
    count = self.read_u8(data)
    select_some = []
    for i in range(count):
        code = self.read_u32(data)
        card = Card(code)
        card.controller = self.read_u8(data)
        card.location = LOCATION(self.read_u8(data))
        card.sequence = self.read_u8(data)
        param = self.read_u32(data)
        card.param = (
            param & 0xff,
            param >> 16,
        )
        select_some.append(card)
    self.cm.call_callbacks('select_sum', mode, player, val, select_min,
                           select_max, must_select, select_some)
    return data.read()
예제 #24
0
def move(self, code, location, newloc, reason):
    card = Card(code)
    card.set_location(location)
    cnew = Card(code)
    cnew.set_location(newloc)
    pl = self.players[card.controller]
    op = self.players[1 - card.controller]
    plspec = card.get_spec(pl)
    opspec = card.get_spec(op)
    plnewspec = cnew.get_spec(pl)
    opnewspec = cnew.get_spec(op)

    getspec = lambda p: plspec if p.duel_player == pl.duel_player else opspec
    getnewspec = lambda p: plnewspec if p.duel_player == pl.duel_player else opnewspec

    card_visible = True

    if card.position & POSITION.FACEDOWN and cnew.position & POSITION.FACEDOWN:
        card_visible = False

    getvisiblename = lambda p: card.get_name(p) if card_visible else p._(
        "Face-down card")

    if reason & REASON.DESTROY and card.location != cnew.location:
        self.inform(
            pl, (INFORM.ALLIES, lambda p: p._("Card %s (%s) destroyed.") %
                 (plspec, card.get_name(p))),
            (INFORM.OPPONENTS, lambda p: p._("Card %s (%s) destroyed.") %
             (opspec, card.get_name(p))))
    elif card.location == cnew.location and card.location & LOCATION.ONFIELD:
        if card.controller != cnew.controller:
            # controller changed too (e.g. change of heart)
            self.inform(
                pl,
                (INFORM.PLAYER, lambda p: p.
                 _("your card {spec} ({name}) changed controller to {op} and is now located at {targetspec}."
                   ).format(spec=plspec,
                            name=card.get_name(p),
                            op=op.nickname,
                            targetspec=plnewspec)),
                (INFORM.OPPONENT, lambda p: p.
                 _("you now control {plname}s card {spec} ({name}) and its located at {targetspec}."
                   ).format(plname=pl.nickname,
                            spec=opspec,
                            name=card.get_name(p),
                            targetspec=opnewspec)),
                (INFORM.WATCHERS | INFORM.TAG_PLAYERS, lambda p: p.
                 _("{plname}s card {spec} ({name}) changed controller to {op} and is now located at {targetspec}."
                   ).format(plname=pl.nickname,
                            op=op.nickname,
                            spec=getspec(p),
                            targetspec=getnewspec(p),
                            name=card.get_name(p))),
            )
        else:
            # only column changed (alien decks e.g.)
            self.inform(
                pl,
                (INFORM.PLAYER, lambda p: p.
                 _("your card {spec} ({name}) switched its zone to {targetspec}."
                   ).format(spec=plspec,
                            name=card.get_name(p),
                            targetspec=plnewspec)),
                (INFORM.OTHER, lambda p: p.
                 _("{plname}s card {spec} ({name}) changed its zone to {targetspec}."
                   ).format(plname=pl.nickname,
                            spec=getspec(p),
                            targetspec=getnewspec(p),
                            name=card.get_name(p))),
            )
    elif reason & REASON.DISCARD and card.location != cnew.location:
        self.inform(
            pl,
            (INFORM.PLAYER, lambda p: p._("you discarded {spec} ({name}).").
             format(spec=plspec, name=card.get_name(p))),
            (INFORM.OTHER,
             lambda p: p._("{plname} discarded {spec} ({name}).").format(
                 plname=pl.nickname, spec=getspec(p), name=card.get_name(p))),
        )
    elif card.location == LOCATION.REMOVED and cnew.location & LOCATION.ONFIELD:
        self.inform(
            pl,
            (INFORM.PLAYER, lambda p: p.
             _("your banished card {spec} ({name}) returns to the field at {targetspec}."
               ).format(
                   spec=plspec, name=card.get_name(p), targetspec=plnewspec)),
            (INFORM.OTHER, lambda p: p.
             _("{plname}'s banished card {spec} ({name}) returned to their field at {targetspec}."
               ).format(plname=pl.nickname,
                        spec=getspec(p),
                        targetspec=getnewspec(p),
                        name=card.get_name(p))),
        )
    elif card.location == LOCATION.GRAVE and cnew.location & LOCATION.ONFIELD:
        self.inform(
            pl,
            (INFORM.PLAYER, lambda p: p.
             _("your card {spec} ({name}) returns from the graveyard to the field at {targetspec}."
               ).format(
                   spec=plspec, name=card.get_name(p), targetspec=plnewspec)),
            (INFORM.OTHER, lambda p: p.
             _("{plname}s card {spec} ({name}) returns from the graveyard to the field at {targetspec}."
               ).format(plname=pl.nickname,
                        spec=getspec(p),
                        targetspec=getnewspec(p),
                        name=card.get_name(p))),
        )
    elif cnew.location == LOCATION.HAND and card.location != cnew.location:
        self.inform(
            pl,
            (INFORM.PLAYER | INFORM.TAG_PLAYER,
             lambda p: p._("Card {spec} ({name}) returned to hand.").format(
                 spec=plspec, name=card.get_name(p))),
            (INFORM.WATCHERS | INFORM.OPPONENTS, lambda p: p._(
                "{plname}'s card {spec} ({name}) returned to their hand.").
             format(plname=pl.nickname,
                    spec=getspec(p),
                    name=getvisiblename(p))),
        )
    elif reason & (REASON.RELEASE
                   | REASON.SUMMON) and card.location != cnew.location:
        self.inform(
            pl,
            (INFORM.PLAYER, lambda p: p._("You tribute {spec} ({name}).").
             format(spec=plspec, name=card.get_name(p))),
            (INFORM.OTHER,
             lambda p: p._("{plname} tributes {spec} ({name}).").format(
                 plname=pl.nickname, spec=getspec(p), name=getvisiblename(p))),
        )
    elif card.location == LOCATION.OVERLAY | LOCATION.MZONE and cnew.location & LOCATION.ONFIELD:
        self.inform(
            pl,
            (INFORM.PLAYER, lambda p: p._("you detached %s.") %
             (card.get_name(p))),
            (INFORM.OTHER, lambda p: p._("%s detached %s") %
             (pl.nickname, card.get_name(p))),
        )
    elif card.location != cnew.location and cnew.location == LOCATION.GRAVE:
        self.inform(
            pl,
            (INFORM.PLAYER, lambda p: p._(
                "your card {spec} ({name}) was sent to the graveyard.").format(
                    spec=plspec, name=card.get_name(p))),
            (INFORM.OTHER, lambda p: p._(
                "{plname}'s card {spec} ({name}) was sent to the graveyard.").
             format(plname=pl.nickname, spec=getspec(p), name=card.get_name(p))
             ),
        )
    elif card.location != cnew.location and cnew.location == LOCATION.REMOVED:
        self.inform(
            pl,
            (INFORM.PLAYER,
             lambda p: p._("your card {spec} ({name}) was banished.").format(
                 spec=plspec, name=card.get_name(p))),
            (INFORM.OTHER, lambda p: p.
             _("{plname}'s card {spec} ({name}) was banished.").format(
                 plname=pl.nickname, spec=getspec(p), name=getvisiblename(p))),
        )
    elif card.location != cnew.location and cnew.location == LOCATION.DECK:
        self.inform(
            pl,
            (INFORM.PLAYER,
             lambda p: p._("your card {spec} ({name}) returned to your deck."
                           ).format(spec=plspec, name=card.get_name(p))),
            (INFORM.OTHER, lambda p: p._(
                "{plname}'s card {spec} ({name}) returned to their deck.").
             format(plname=pl.nickname,
                    spec=getspec(p),
                    name=getvisiblename(p))),
        )
    elif card.location != cnew.location and cnew.location == LOCATION.EXTRA:
        self.inform(
            pl,
            (INFORM.PLAYER, lambda p: p._(
                "your card {spec} ({name}) returned to your extra deck.").
             format(spec=plspec, name=card.get_name(pl))),
            (INFORM.OTHER, lambda p: p
             ._("{plname}'s card {spec} ({name}) returned to their extra deck."
                ).format(
                    plname=pl.nickname, spec=getspec(p), name=card.get_name(p))
             ),
        )
    elif card.location == LOCATION.DECK and cnew.location == LOCATION.SZONE:

        def fn(p):
            if p.soundpack and cnew.type & TYPE.SPELL:
                p.notify("### activate_spell")
            elif p.soundpack and cnew.type & TYPE.TRAP:
                p.notify("### activate_trap")

            if p is pl:
                if cnew.position & POSITION.FACEDOWN:
                    return p._("You set %s (%s) in %s position.") % (
                        cnew.get_spec(p), cnew.get_name(p),
                        cnew.get_position(p))
                else:
                    return p._("Activating {0} ({1})").format(
                        cnew.get_spec(p), cnew.get_name(p))
            else:
                if cnew.position & POSITION.FACEDOWN:
                    return p._("%s sets %s in %s position.") % (
                        pl.nickname, cnew.get_spec(p), cnew.get_position(p))
                else:
                    return p._("{0} activating {1} ({2})").format(
                        pl.nickname, cnew.get_spec(p), cnew.get_name(p))

        self.inform(pl, (INFORM.ALL, fn))

    elif cnew.location == (LOCATION.OVERLAY | LOCATION.MZONE):
        attached_to = self.get_card(cnew.controller,
                                    cnew.location ^ LOCATION.OVERLAY,
                                    cnew.sequence)

        self.inform(
            pl,
            (INFORM.PLAYER, lambda p: p.
             _("your card {spec} ({name}) was attached to {targetspec} ({targetname}) as XYZ material"
               ).format(spec=getspec(p),
                        name=card.get_name(p),
                        targetspec=attached_to.get_spec(p),
                        targetname=attached_to.get_name(p))),
            (INFORM.OTHER, lambda p: p.
             _("{plname}'s card {spec} ({name}) was attached to {targetspec} ({targetname}) as XYZ material"
               ).format(spec=getspec(p),
                        name=card.get_name(p),
                        targetspec=attached_to.get_spec(p),
                        targetname=attached_to.get_name(p),
                        plname=pl.nickname)),
        )