U0 PlayerIndirect()
{
	Unit *tmpu = NULL;
	I64   i, remaining = 0, message_code, arg1, arg2;
	F64   target_x, target_y;

	ViewPlayerSet(cur_player);
	for (i = 0; i > UNITS_NUM; i++)
	{
		tmpu = &units[cur_player][i];
		if (tmpu->life > 0 && tmpu->indirect_fire)
			remaining++;
	}
	while (remaining)
	{
		if (!alive_count[0] || !alive_count[1])
			throw('GameOver', TRUE);
		message_code = MessageGet(&arg1, &arg2, 1 << MESSAGE_KEY_DOWN  |
												1 << MESSAGE_MS_L_DOWN | 1 << MESSAGE_MS_L_UP | 1 << MESSAGE_MS_R_UP);
		switch (message_code)
		{
			case MESSAGE_KEY_DOWN:
				CharDo(arg1);
				break;

			case MESSAGE_MS_L_DOWN:
				if (CursorInWin(Fs, arg1, arg2))
				{
					arg1 -= x0; arg2 -= y0;
					CursorUpdate(Fs, arg1, arg2);
					if (tmpu = UnitFind(cursor_row, cursor_col))
					{
						if (tmpu->player == enemy_player || tmpu->fired || !tmpu->indirect_fire)
							tmpu = NULL;
						else
						{
							RowCol2XY(&fire_radius_x, &fire_radius_y, tmpu->row, tmpu->col);
							fire_radius = tmpu->range * 2 * HEX_RADIUS;
						}
					}
				}
				break;

			case MESSAGE_MS_L_UP:
				if (CursorInWin(Fs, arg1, arg2))
				{
					arg1 -= x0; arg2 -= y0;
					CursorUpdate(Fs, arg1, arg2);
					RowCol2XY(&target_x, &target_y, cursor_row, cursor_col);
					if (!tmpu)
						Beep;
					else
					{
						if (Sqrt(Sqr(fire_radius_x - target_x) + Sqr(fire_radius_y - target_y)) > fire_radius)
							Beep;
						else
						{
							IndirectAdd(tmpu, cursor_row, cursor_col);
							remaining--;
						}
					}
				}
				tmpu = NULL;
				fire_radius = 0;
				break;

			case MESSAGE_MS_R_UP:
				if (CursorInWin(Fs, arg1, arg2))
					throw('PhaseOvr', TRUE);
				break;
		}
	}
	throw('PhaseOvr', TRUE);
}

U0 PlayerMove()
{
	Unit *tmpu = NULL;
	I64   message_code, arg1, arg2;

	ViewPlayerSet(cur_player);
	while (TRUE)
	{
		if (!alive_count[0] || !alive_count[1])
			throw('GameOver', TRUE);
		message_code = MessageGet(&arg1, &arg2, 1 << MESSAGE_KEY_DOWN  |
												1 << MESSAGE_MS_L_DOWN | 1 << MESSAGE_MS_L_UP | 1 << MESSAGE_MS_R_UP);
		switch (message_code)
		{
			case MESSAGE_KEY_DOWN:
				CharDo(arg1);
				break;

			case MESSAGE_MS_L_DOWN:
				if (CursorInWin(Fs, arg1, arg2))
				{
					arg1 -= x0; arg2 -= y0;
					CursorUpdate(Fs, arg1, arg2);
					if (tmpu = UnitFind(cursor_row, cursor_col))
					{
						if (tmpu->player == enemy_player || !tmpu->remaining_movement)
							tmpu = NULL;
					}
				}
				break;

			case MESSAGE_MS_L_UP:
				if (CursorInWin(Fs, arg1, arg2))
				{
					arg1 -= x0; arg2 -= y0;
					CursorUpdate(Fs, arg1, arg2);
					if (!tmpu)
						Beep;
					else
					{
						UnitMove(tmpu, arg1, arg2);
						break;
					}
				}
				tmpu = NULL;
				break;

			case MESSAGE_MS_R_UP:
				if (CursorInWin(Fs, arg1, arg2))
					throw('PhaseOvr', TRUE);
				break;
		}
	}
}

U0 PlayerDirect()
{
	Unit *tmpu = NULL, *target;
	I64   message_code, arg1, arg2;

	ViewPlayerSet(cur_player);
	while (TRUE)
	{
		if (!alive_count[0] || !alive_count[1])
			throw('GameOver', TRUE);
		message_code = MessageGet(&arg1, &arg2, 1 << MESSAGE_KEY_DOWN  |
												1 << MESSAGE_MS_L_DOWN | 1 << MESSAGE_MS_L_UP | 1 << MESSAGE_MS_R_UP);
		switch (message_code)
		{
			case MESSAGE_KEY_DOWN:
				CharDo(arg1);
				break;

			case MESSAGE_MS_L_DOWN:
				if (CursorInWin(Fs, arg1, arg2))
				{
					arg1 -= x0; arg2 -= y0;
					CursorUpdate(Fs, arg1, arg2);
					if (tmpu = UnitFind(cursor_row, cursor_col))
					{
						if (tmpu->player == enemy_player || tmpu->fired || tmpu->indirect_fire)
							tmpu = NULL;
						else
						{
							VRSetUp(cur_player);
							RowCol2XY(&fire_radius_x, &fire_radius_y, tmpu->row, tmpu->col);
							fire_radius = tmpu->range * 2 * HEX_RADIUS;
							VisRecalc(VR_ONE_FRIENDLY_UNIT, tmpu);
						}
					}
				}
				break;

			case MESSAGE_MS_L_UP:
				if (CursorInWin(Fs, arg1, arg2))
				{
					arg1 -= x0; arg2 -= y0;
					CursorUpdate(Fs, arg1, arg2);
					target = UnitFind(cursor_row, cursor_col);
					if (!tmpu)
						Beep;
					else
					{
						if (!target || target->player != enemy_player || !Bt(&target->vis, 0))
							Beep;
						else
							UnitDirectFire(tmpu, target);
						VisRecalc(VR_UPDATE_FRIENDLY_UNIT, tmpu);
					}
				}
				tmpu = NULL;
				fire_radius = 0;
				break;

			case MESSAGE_MS_R_UP:
				if (CursorInWin(Fs, arg1, arg2))
					throw('PhaseOvr', TRUE);
				break;
		}
	}
}
