bool GameChat::handle_special_commands(GameState* gs, const std::string& command) { ChatMessage printed; const char* content; PlayerInst* p = gs->local_player(); //Spawn monster if (starts_with(command, "!spawn ", &content)) { const char* rest = content; int amnt = strtol(content, (char**)&rest, 10); if (content == rest) amnt = 1; rest = skip_whitespace(rest); int enemy = get_enemy_by_name(rest, false); if (enemy == -1) { printed.message = "No such monster, '" + std::string(rest) + "'!"; printed.message_colour = Colour(255, 50, 50); } else { printed.message = std::string(rest) + " has spawned !"; generate_enemy_after_level_creation(gs, enemy, amnt); printed.message_colour = Colour(50, 255, 50); } add_message(printed); return true; } //Set game speed if (starts_with(command, "!gamespeed ", &content)) { int gamespeed = squish(atoi(content), 1, 200); gs->game_settings().time_per_step = gamespeed; printed.message = std::string("Game speed set."); printed.message_colour = Colour(50, 255, 50); add_message(printed); return true; } //Gain XP if (starts_with(command, "!gainxp ", &content)) { int xp = atoi(content); if (xp > 0 && xp < 999999) { printed.message = std::string("You have gained ") + content + " experience."; printed.message_colour = Colour(50, 255, 50); add_message(printed); p->gain_xp(gs, xp); } else { printed.message = "Invalid experience amount!"; printed.message_colour = Colour(255, 50, 50); add_message(printed); } return true; } //Create item if (starts_with(command, "!item ", &content)) { const char* rest = content; int amnt = strtol(content, (char**)&rest, 10); if (content == rest) amnt = 1; rest = skip_whitespace(rest); int item = get_item_by_name(rest, false); if (item == -1) { printed.message = "No such item, '" + std::string(rest) + "'!"; printed.message_colour = Colour(255, 50, 50); } else { printed.message = std::string(rest) + " put in your inventory !"; p->stats().equipment.inventory.add(Item(item), amnt); printed.message_colour = Colour(50, 255, 50); } add_message(printed); return true; } //Kill all monsters if (starts_with(command, "!killall", &content)) { MonsterController& mc = gs->monster_controller(); for (int i = 0; i < mc.monster_ids().size(); i++) { EnemyInst* inst = (EnemyInst*)gs->get_instance(mc.monster_ids()[i]); if (inst) { inst->damage(gs, 99999); } } printed.message = "Killed all monsters."; printed.message_colour = Colour(50, 255, 50); add_message(printed); return true; } lua_State* L = gs->get_luastate(); static LuaValue script_globals; if (script_globals.empty()) { script_globals.table_initialize(L); // script_globals.push(L); // int script = lua_gettop(L); // lua_pushvalue(L, LUA_GLOBALSINDEX); // lua_setmetatable(L, script); // lua_pop(L, 1); } lua_push_gameinst(L, p); script_globals.table_pop_value(L, "player"); lua_push_combatstats(L, p); script_globals.table_pop_value(L, "stats"); //Run lua command if (starts_with(command, "!lua ", &content)) { // std::string luafunc = std::string(content); int prior_top = lua_gettop(L); luaL_loadstring(L, content); if (lua_isstring(L, -1)) { const char* val = lua_tostring(L, -1); add_message(val, /*iserr ? Colour(255,50,50) :*/ Colour(120, 120, 255)); return true; } int lfunc = lua_gettop(L); script_globals.push(L); lua_setfenv(L, lfunc); bool iserr = (lua_pcall(L, 0, LUA_MULTRET, 0) != 0); int current_top = lua_gettop(L); for (; prior_top < current_top; prior_top++) { if (lua_isstring(L, -1)) { const char* val = lua_tostring(L, -1); add_message(val, iserr ? Colour(255, 50, 50) : Colour(120, 120, 255)); } lua_pop(L, 1); } return true; } //Run lua file if (starts_with(command, "!luafile ", &content)) { int prior_top = lua_gettop(L); int err_func = luaL_loadfile(L, content); if (err_func) { const char* val = lua_tostring(L, -1); add_message(val, Colour(120, 120, 255)); lua_pop(L, 1); return true; } int lfunc = lua_gettop(L); script_globals.push(L); lua_setfenv(L, lfunc); bool err_call = (lua_pcall(L, 0, 0, 0) != 0); if (err_call) { const char* val = lua_tostring(L, -1); add_message(val, Colour(120, 120, 255)); lua_pop(L, 1); } return true; } return false; }
void MonsterController::register_enemy(GameInst* enemy) { mids.push_back(enemy->id); RVO::Vector2 enemy_position(enemy->x, enemy->y); EnemyInst* e = (EnemyInst*)enemy; EffectiveStats& estats = e->effective_stats(); EnemyBehaviour& eb = e->behaviour(); }
void MonsterController::post_draw(GameState* gs) { PlayerInst* player = gs->local_player(); if (!player) { return; } EnemyInst* target = (EnemyInst*)gs->get_instance(player->target()); if (!target) { return; } ldraw::draw_circle_outline(COL_GREEN.alpha(140), on_screen(gs, target->ipos()), target->target_radius + 5, 2); }
static void push_inst_name(lua_State* L, GameInst* inst) { PlayerInst* p = dynamic_cast<PlayerInst*>(inst); if (p) { // lua_pushlstring(L, p->); //TODO lua_pushstring(L, "Your ally"); } else { EnemyInst* e = dynamic_cast<EnemyInst*>(inst); if (e) { std::string& name = e->etype().name; lua_pushlstring(L, name.c_str(), name.size()); } else { lua_pushnil(L); } } }
void PlayerInst::use_weapon(GameState* gs, const GameAction& action) { WeaponEntry& wentry = weapon().weapon_entry(); MTwist& mt = gs->rng(); const int MAX_MELEE_HITS = 10; EffectiveStats& estats = effective_stats(); if (!cooldowns().can_doaction()) { return; } Pos start(x, y); Pos actpos(action.action_x, action.action_y); if (wentry.uses_projectile && !equipment().has_projectile()) { return; } int cooldown = 0; if (equipment().has_projectile()) { const Projectile& projectile = equipment().projectile; ProjectileEntry& pentry = projectile.projectile_entry(); item_id item = get_item_by_name(pentry.name.c_str()); int weaprange = std::max(wentry.range, pentry.range); AttackStats weaponattack(weapon()); bool wallbounce = false; int nbounces = 0; float movespeed = pentry.speed; cooldown = std::max(wentry.cooldown, pentry.cooldown); //XXX: Horrible hack REMOVE THIS LATER if (class_stats().class_type().name == "Archer" && pentry.weapon_class == "bows") { int xplevel = class_stats().xplevel; float movebonus = class_stats().xplevel / 4.0f; if (movebonus > 2) { movebonus = 2; } float cooldown_mult = 1.0f - (class_stats().xplevel - 1) / 20.0f; if (cooldown_mult <= 0.85) { cooldown_mult = 0.85; } cooldown *= cooldown_mult; movespeed += movebonus; if (xplevel >= 3 && core_stats().mp >= 5) { nbounces = 2; core_stats().mp -= 5; } } GameInst* bullet = new ProjectileInst(projectile, effective_atk_stats(mt, weaponattack), id, start, actpos, movespeed, weaprange, NONE, wallbounce, nbounces); gs->add_instance(bullet); equipment().use_ammo(); } else { int weaprange = wentry.range + this->radius + TILE_SIZE / 2; float mag = distance_between(actpos, Pos(x, y)); if (mag > weaprange) { float dx = actpos.x - x, dy = actpos.y - y; actpos = Pos(x + dx / mag * weaprange, y + dy / mag * weaprange); } GameInst* enemies[MAX_MELEE_HITS]; int max_targets = std::min(MAX_MELEE_HITS, wentry.max_targets); int numhit = get_targets(gs, this, actpos.x, actpos.y, wentry.dmgradius, enemies, max_targets); if (numhit == 0) { return; } for (int i = 0; i < numhit; i++) { EnemyInst* e = (EnemyInst*)enemies[i]; lua_hit_callback(gs->get_luastate(), wentry.on_hit_func, this, e); if (attack(gs, e, AttackStats(equipment().weapon))) { PlayerData& pc = gs->player_data(); signal_killed_enemy(); char buffstr[32]; int amnt = round( double(e->xpworth()) / pc.all_players().size()); players_gain_xp(gs, amnt); snprintf(buffstr, 32, "%d XP", amnt); gs->add_instance( new AnimatedInst(Pos(e->x - 5, e->y - 5), -1, 25, Posf(), Posf(), AnimatedInst::DEPTH, buffstr, Colour(255, 215, 11))); } } cooldown = wentry.cooldown; } cooldowns().reset_action_cooldown(cooldown * estats.cooldown_mult); reset_rest_cooldown(); }
void MonsterController::pre_step(GameState* gs) { perf_timer_begin(FUNCNAME); CollisionAvoidance& coll_avoid = gs->collision_avoidance(); PlayerInst* local_player = gs->local_player(); std::vector<EnemyOfInterest> eois; players = gs->players_in_level(); //Update 'mids' to only hold live objects std::vector<obj_id> mids2; mids2.reserve(mids.size()); mids.swap(mids2); for (int i = 0; i < mids2.size(); i++) { EnemyInst* e = (EnemyInst*)gs->get_instance(mids2[i]); if (e == NULL) continue; EnemyBehaviour& eb = e->behaviour(); eb.step(); //Add live instances back to monster id list mids.push_back(mids2[i]); int closest_player_index = find_player_to_target(gs, e); if (eb.current_action == EnemyBehaviour::INACTIVE && e->cooldowns().is_hurting()) { eb.current_action = EnemyBehaviour::CHASING_PLAYER; } if (closest_player_index == -1 && eb.current_action == EnemyBehaviour::CHASING_PLAYER) { eb.current_action = EnemyBehaviour::INACTIVE; e->target() = NONE; } if (eb.current_action == EnemyBehaviour::CHASING_PLAYER) eois.push_back( EnemyOfInterest(e, closest_player_index, inst_distance(e, players[closest_player_index]))); else if (eb.current_action == EnemyBehaviour::INACTIVE) monster_wandering(gs, e); else //if (eb.current_action == EnemyBehaviour::FOLLOWING_PATH) monster_follow_path(gs, e); } set_monster_headings(gs, eois); //Update player positions for collision avoidance simulator for (int i = 0; i < players.size(); i++) { PlayerInst* p = players[i]; coll_avoid.set_position(p->collision_simulation_id(), p->x, p->y); } for (int i = 0; i < mids.size(); i++) { EnemyInst* e = (EnemyInst*)gs->get_instance(mids[i]); lua_State* L = gs->luastate(); lua_gameinst_callback(L, e->etype().step_event.get(L), e); update_velocity(gs, e); simul_id simid = e->collision_simulation_id(); coll_avoid.set_position(simid, e->rx, e->ry); coll_avoid.set_preferred_velocity(simid, e->vx, e->vy); } coll_avoid.step(); for (int i = 0; i < mids.size(); i++) { EnemyInst* e = (EnemyInst*)gs->get_instance(mids[i]); update_position(gs, e); } perf_timer_end(FUNCNAME); }