Exemple #1
0
/*
 * Set up the required initial conditions for a match, and switch to playing state
 */
void start_game()
{
	/* Seed the RNG */
	srand(TCNT1);

	/* Load in the sprites */
	reticule_SPR = reticule(0);

	/* Generate and draw a level */
	clear_screen();
	free((void*) level_map);
	level_map = generate_flat(WIDTH, 129);	
	if(level_map != NULL)
		draw_level(level_map, SILVER, 0, WIDTH - 1);
	
	/* Set up the players in the field */
	playersX = malloc(players * sizeof(int16_t));
	playersY = malloc(players * sizeof(int16_t));
	players_HP = malloc(players * sizeof(uint8_t));
	if(playersX == NULL || playersY == NULL || players_HP == NULL)
	{
		display_string("Out of memory error!");
		return;
	}
	uint8_t i;
	for(i = 0; i < players; i++)
	{
		playersX[i] = (i + 1) * WIDTH / (players + 1);
		playersY[i] = 120;
		players_HP[i] = MAX_PLAYER_HP;

		free_sprite(player_SPR);
		player_SPR = botleft(i);
		fill_sprite(player_SPR, playersX[i], playersY[i], HEIGHT_NO_UI, WIDTH);
	}

	/* Pick a random player to ... go last
	 * First call to start_turn will cycle to next player. Poor sod. */
	current_player = rand() % players;

	reticuleX = (playersX[current_player] + (RETICULE_DISTANCE * ml_cos(position))/100);
	reticuleY = (playersY[current_player] + (RETICULE_DISTANCE * ml_sin(position))/100);

	/* Initialise movement variables */
	direction = 0;
	launch_speed = 0;

	/* Draw the UI */
	display_string_xy("POWER:", POWER_LABEL_X, POWER_LABEL_Y);
	fill_rectangle(power_outline, WHITE);
	fill_rectangle(power_empty, BLACK);
	display_string_xy("WIND:", WIND_LABEL_X, WIND_LABEL_Y);
	fill_rectangle(wind_outline, WHITE);
	fill_rectangle(wind_empty, BLACK);

	/* Start the first player's turn */
	start_turn();
}
Report* Fight::start(ls::VM& vm, ls::VM& vm_v1) {

	Simulator::fight = this;

	for (auto& team : teams) {
		for (auto& entity : team->entities) {
			entities.insert({entity->id, entity});
			order.addEntity(entity);
			entity->ai->compile(vm, vm_v1);
		}
	}

	actions.add(new ActionStartFight());

	while (order.getTurn() <= MAX_TURNS) {

		auto entity = order.current();
		Simulator::entity = entity;
		vm.output = entity->debug_output;
		vm_v1.output = entity->debug_output;

		LOG << "Turn of " << entity->name << " (" << entity->id << "), AI " << entity->ai->name << "..." << std::endl;
		actions.add(new ActionEntityTurn(entity));
		entity->start_turn();
		try {
			entity->ai->execute(vm, vm_v1);
		} catch (ls::vm::ExceptionObj* ex) {
			LOG << ex->to_string(true);
			// vm.last_exception = nullptr;
			// vm_v1.last_exception = nullptr;
			if (ex->type == ls::vm::Exception::OPERATION_LIMIT_EXCEEDED) {
				actions.add(new ActionAIError(entity));
				// TODO Add Breaker Trophy
			}
			// TODO delete ex
		}
		vm.operations = 0;
		entity->end_turn();
		actions.add(new ActionEndTurn(entity));

		if (is_finished()) {
			break;
		}
		if (order.next()) {
			actions.add(new ActionNewTurn(order.getTurn()));
			LOG << "Turn " << order.getTurn() << std::endl;
		}
	}

	Simulator::entity = nullptr;

	Report* report = new Report(this);
	report->actions = &actions;
	return report;
}
Exemple #3
0
/*
 * Perform the given action.
 */
static void perform_act(game *g, action a)
{
	player *p, *opp;
	int old_phase;

	/* Get player pointers */
	p = &g->p[g->turn];
	opp = &g->p[!g->turn];

	/* Remember current phase */
	old_phase = p->phase;

	/* Switch on action */
	switch (a.act)
	{
		/* No action, advance phase counter */
		case ACT_NONE:
		{
			/* Advance phase counter */
			p->phase++;

			/* Take care of bookkeeping */
			switch (old_phase)
			{
				/* Start of turn */
				case PHASE_START:

					/* Start turn */
					start_turn(g);

					/* Done */
					break;

				/* After support/booster */
				case PHASE_AFTER_SB:

					/* End support phase */
					end_support(g);
					
					/* Done */
					break;

				/* Refresh hand */
				case PHASE_REFRESH:

					/* Refresh */
					refresh_phase(g);

					/* Done */
					break;

				/* End of turn */
				case PHASE_END:

					/* End current turn */
					end_turn(g);

					/* Done */
					break;

				/* Move to next player */
				case PHASE_OVER:

					/* Player is done */
					p->phase = PHASE_NONE;

					/* Next player */
					g->turn = !g->turn;

					/* Start opponent's turn */
					opp->phase = PHASE_START;

					/* Done (completely) */
					return;
			}

			/* Clear last played card */
			p->last_played = 0;

			/* Done */
			break;
		}

		/* Retreat */
		case ACT_RETREAT:
		{
			/* Retreat */
			retreat(g);

			/* Done */
			break;
		}

		/* Retrieve a card */
		case ACT_RETRIEVE:
		{
			/* Set last played */
			p->last_played = a.index;

			/* Retrieve card */
			retrieve_card(g, a.arg);

			/* Done */
			break;
		}

		/* Play a card */
		case ACT_PLAY:
		{
			/* Set last played */
			p->last_played = a.index;

			/* Play card */
			play_card(g, a.arg, 0, 0);

			/* Done */
			break;
		}

		/* Play a card without special effect */
		case ACT_PLAY_NO:
		{
			/* Set last played */
			p->last_played = a.index;

			/* Play card */
			play_card(g, a.arg, 1, 0);

			/* Done */
			break;
		}

		/* Announce power */
		case ACT_ANN_FIRE:
		case ACT_ANN_EARTH:
		{
			/* Increment phase counter */
			p->phase++;

			/* Announce power */
			announce_power(g, a.act - ACT_ANN_FIRE);

			/* Done */
			break;
		}

		/* Use card special power */
		case ACT_USE:
		{
			/* Use card */
			use_special(g, a.arg);

			/* Done */
			break;
		}

		/* Satisfy opponent's "discard" card */
		case ACT_SATISFY:
		{
			/* Satisfy requirement */
			satisfy_discard(g, a.arg);

			/* Done */
			break;
		}

		/* Land a ship */
		case ACT_LAND:
		{
			/* Set last played */
			p->last_played = a.index;

			/* Land ship */
			land_ship(g, a.arg);

			/* Done */
			break;
		}

		/* Load a card onto a ship */
		case ACT_LOAD:
		{
			/* Set last played */
			p->last_played = a.index;

			/* Load card */
			load_card(g, a.arg, a.target);

			/* Done */
			break;
		}

		/* Play a bluff card */
		case ACT_BLUFF:
		{
			/* Set last played */
			p->last_played = a.index;

			/* Play bluff */
			play_bluff(g, a.arg);

			/* Done */
			break;
		}

		/* Reveal a bluff card */
		case ACT_REVEAL:
		{
			/* Set last played */
			p->last_played = a.index;

			/* Reveal bluff */
			reveal_bluff(g, g->turn, a.arg);

			/* Done */
			break;
		}
	}
}
Exemple #4
0
/*
 * Main function to run one tick of the game
 */
int run_game()
{
	cli();

	/* Movement phase */
	if(game_state == 1)
	{
		/* Move the reticule based on readings from the rotary encoder */
		int16_t newRX = (playersX[current_player] + (RETICULE_DISTANCE * ml_cos(position))/100);
		int16_t newRY = (playersY[current_player] + (RETICULE_DISTANCE * ml_sin(position))/100);
		
		rectangle reticuleOld = {reticuleX - reticule_SPR->width / 2, reticuleX + reticule_SPR->width / 2 - 1, reticuleY - reticule_SPR->height / 2, reticuleY + reticule_SPR->height / 2 - 1};
		draw_background(level_map, SILVER, reticuleOld, HEIGHT_NO_UI, WIDTH);

		//fill_rectangle(reticuleOld, BLACK);
		if(newRX >= 0 && newRX < WIDTH && newRY >= 0 && newRY < HEIGHT)
			fill_sprite(reticule_SPR, newRX, newRY, HEIGHT_NO_UI, WIDTH);
	
		reticuleX = newRX;
		reticuleY = newRY;

		/* Read firing input */
		if (get_switch_long(_BV(SWC)))
		{
			game_state = 3;
			return 0;
		}		

		/* Read directional input.*/
		if (get_switch_rpt(_BV(SWE))) 
		{
			direction = 4;
			free_sprite(player_SPR);
			player_SPR = botright(current_player);
		}
		else if (get_switch_rpt(_BV(SWW)))
		{
			direction = -4;
			free_sprite(player_SPR);
			player_SPR = botleft(current_player);
		}
		else
		{
			direction = 0;
			return 0;
		}

		/* Move the player */
		int16_t newX = playersX[current_player] + direction;
		int16_t newY = ml_min(level_map[newX - PLAYER_WIDTH], level_map[newX + PLAYER_WIDTH - 1]) - PLAYER_HEIGHT;

		int8_t i;
		int8_t player_collision = 0;
		for(i = 0; i < players; i++)
		{
			if(players_HP[i] != 0 && i != current_player && newX >= playersX[i] - PLAYER_WIDTH && newX <= playersX[i] + PLAYER_WIDTH - 1)
			{
				player_collision = 1;
				break;
			}				
		}

		/* Cancel movement if trying to climb to high or off the sides of the screen */
		if(player_collision || playersY[current_player] - newY > MAX_CLIMB_HEIGHT || newX <= PLAYER_WIDTH || newX + PLAYER_WIDTH > WIDTH)
		{
			/* DEBUGGING prints: */
			//display_string_xy("Error\n", 10, 10);
			//ml_printf("Cannot move there... (%u,%u) to (%u,%u)", playersX[0], playersY[0], newX, newY);
			return 0;
		}
		
		rectangle playerOld = {playersX[current_player] - PLAYER_WIDTH, playersX[current_player] + PLAYER_WIDTH - 1, playersY[current_player] - PLAYER_HEIGHT, playersY[current_player] + PLAYER_HEIGHT - 1};

		fill_rectangle(playerOld, BLACK);
		fill_sprite(player_SPR, newX, newY, HEIGHT_NO_UI, WIDTH);
		
		playersX[current_player] = newX;
		playersY[current_player] = newY;
	}
	/* Projectile phase (missile in the air) */
	else if(game_state == 2)
	{
		/* Find the new position of the projectile */
		int16_t newX = projectileX + proVelX/1000;
		int16_t newY = projectileY + proVelY/1000;
		
		rectangle projectileOld = {projectileX, projectileX, projectileY, projectileY};
		fill_rectangle(projectileOld, BLACK);

		/* End turn if projectile goes off the sides of the level */
		if(newX < 0 || newX > WIDTH)
		{
			start_turn();
			return 0;
		}
		
		/* If the new position is in the ground, EXPLODE!
		 * (Also, if off the bottom of the level) */
		if(newY >= level_map[newX] || newY > HEIGHT_NO_UI)
		{
			int i;
			for(i = -EXPLOSION_RADIUS; i <= EXPLOSION_RADIUS; i++)
			{
				/* Make sure that terrain is on screen */
				if(newX + i >= 0 && newX + i < WIDTH)
				{
					uint16_t new_ground_level = newY + ml_sqrt(EXPLOSION_RADIUS * EXPLOSION_RADIUS - i * i);
					if(new_ground_level >= HEIGHT_NO_UI)
						level_map[newX + i] = HEIGHT_NO_UI - 1; //Clamp to bottom of level
					else if(new_ground_level > level_map[newX + i]) //Don't raise the ground level!
						level_map[newX + i] = new_ground_level; 
				}
			}

			draw_level(level_map, SILVER, newX - EXPLOSION_RADIUS, newX + EXPLOSION_RADIUS);

			/* Check players for damage + redraw them */
			for(i = 0; i < players; i++)
			{
				int16_t deltaX = playersX[i] - newX;
				int16_t deltaY = playersY[i] - newY;
				int16_t distance = ml_sqrt(deltaX * deltaX + deltaY * deltaY);
				if(distance < BLAST_RADIUS)
				{
					int16_t damage = ml_clamp(0, players_HP[i], MAX_EXPLOSION_DAMAGE - (distance * MAX_EXPLOSION_DAMAGE / BLAST_RADIUS));
					players_HP[i] -= damage;
				}

				rectangle playerOld = {playersX[i] - PLAYER_WIDTH, playersX[i] + PLAYER_WIDTH - 1, playersY[i] - PLAYER_HEIGHT, playersY[i] + PLAYER_HEIGHT - 1};
				fill_rectangle(playerOld, BLACK);

				/* If the player is still alive, redraw them */
				if(players_HP[i] != 0)
				{
					free_sprite(player_SPR);
					player_SPR = botleft(i);
					playersY[i] = ml_min(level_map[playersX[i] - PLAYER_WIDTH], level_map[playersX[i] + PLAYER_WIDTH - 1]) - PLAYER_HEIGHT;
					fill_sprite(player_SPR, playersX[i], playersY[i], HEIGHT_NO_UI, WIDTH);
				}
			}

			start_turn();
			return 0;
		}	

		rectangle projectileNew = {newX, newX, newY, newY};
		
		/* Continue turn if off top of level, but only draw if projectile onscreen */
		if(newY >= 0)
		{
			fill_rectangle(projectileNew, RED);
		}

		projectileX = newX;
		projectileY = newY;		

		/* Apply gravity and wind */
		proVelY += 500;
		proVelX += (wind_velocity - 10) * 50;
	}
	/* Charging phase */
	else if(game_state == 3)
	{
		/* Increase the launch speed while the fire button is held */
		if (get_switch_state(_BV(SWC)))
		{
			launch_speed++;
			rectangle bar = {POWER_BAR_START, POWER_BAR_START + launch_speed, 231, 236};
			fill_rectangle(bar, WHITE);

			/* Fire once max power is reached */
			if(launch_speed == 100)
				fire_projectile();
		}
		else
		{
			fire_projectile();
		}
	}	
	/* Menu phase */
	else if(game_state == 4)
	{
		if (get_switch_press(_BV(SWE)))
		{
			if(players == 4)
				players = 2;
			else
				players++;
		}
		else if (get_switch_press(_BV(SWW)))
		{
			if(players == 2)
				players = 4;
			else
				players--;
		}

		ml_printf_at("< %u Players >", 5, 115, players);
		
		if (get_switch_long(_BV(SWC)))
		{
			start_game();
		}
	}
	/* End game phase */
	else if(game_state == 5)
	{
		if (get_switch_long(_BV(SWC)))
		{
			start_menu();
		}
	}

	sei();
	
	return 0;
}