/*
 * Wspanialy specjal - silny cios toporem, bardzo oryginalne nieprawdaz? ;)
 * napisany na potrzeby najemnikow napisany przez Morleya
 * Szczegolowe wyliczenia ca znajduja sie w pliku topor.txt
 */

inherit "/cmd/std/command_driver.c";

#include <ss_types.h>
#include <macros.h>
#include <formulas.h>
#include <wa_types.h>
#include "zol_naj.h"
#include "cb_routines.h"

#define DEBUG 1

void
uderz (object gracz, object cel, object bron_poprz);
void
trafienie (object gracz, object cel, object bron);
void
pudlo (object gracz, object cel, object bron);
void
rested (object gracz);

int
kstopor(string str)
{
    object bron = this_player()->query_weapon(W_BOTH) ||
	          this_player()->query_weapon(W_RIGHT) ||
	          this_player()->query_weapon(W_LEFT);
    object *oblist;
    mixed tmp;
    float czas;

    if (!objectp (bron) || bron->query_wt() != W_AXE)
    {
	notify_fail ("Aby wykonac ten cios musisz dzierzyc topor.\n");
	return 0;
    }

    if (this_player()->query_prop(LIVE_I_WKS_REST))
    {
	notify_fail ("Potrzebujesz jeszcze chwili przerwy zeby wykonac kolejne " +
		     "uderzenie.\n");
	return 0;
    }

    if (this_player()->query_prop(LIVE_I_WKS_WAIT))
    {
	notify_fail ("Juz przygotowujesz sie do wykonania ciosu.\n");
	return 0;
    }
    
    if (!stringp (str))
    {
	if (!this_player()->query_attack())
	{
	    notify_fail("Musisz podac kogo chcesz zaatakowac lub z kims juz " +
			"walczyc.\n");
	    return 0;
	}
	else 
	    oblist = ({this_player()->query_attack()});
    }
    else
	oblist = parse_this (str, "%l:" + PL_BIE);

    if (!sizeof (oblist) )
    {
	notify_fail ("kstopor [kogo?]\n");
	return 0;
    }

    if (this_player()->query_skill (WKS_TOPOR) < 5)
    {
	notify_fail ("Z obecnym poziomem wiedzy na temat wykonywania tego ataku, " +
		     "predzej obci" + this_player()->koncowka("albys", "elabys") +
		     " sobie noge niz zranil" + this_player()->koncowka("", "a") +
		     " przeciwnika. Lepiej jeszcze troche pocwicz.\n");
	return 0;
    }

    if (sizeof (oblist) > 1 )
    {
	notify_fail ("Nie uda ci sie uderzyc kilku przeciwnikow na raz. Musisz " +
		     "zdecydowac sie na jednego.\n");
	return 0;
    }
    
    if (tmp = oblist[0]->query_prop (OBJ_M_NO_ATTACK) )
    {
	if (stringp (tmp))
	    notify_fail (tmp);
	else
	    notify_fail ("Cos mowi ci, ze atakowanie " + oblist[0]->query_imie
			 (this_player(), PL_DOP) + " nie byloby wlasciwe.\n");
	return 0;
    }
	    
    if (tmp = environment(oblist[0])->query_prop(ROOM_M_NO_ATTACK) )
    {
	if (stringp (tmp))
	    notify_fail (tmp);
	else
	    notify_fail ("Cos mowi ci, ze atakowanie kogos w tym miejscu nie " +
			 "byloby wlasciwe.\n");
	return 0;
    }

    write  ("Przygotowujesz sie by uderzyc " + oblist[0]->query_imie(this_player(),
	    PL_BIE) + " ze wszystkich sil.\n");

    /*
     * Czas przygotowywania sie do specjala chwilowo staly.
     */

    czas = 10.0;
    
    set_alarm (czas, 0.0, &uderz (this_player(), oblist[0], bron) );
    this_player()->add_prop(LIVE_I_WKS_WAIT, 1);
    return 1;
}

/*
 * Sprawdzanie czy warunkow wykonania ciosu i szans na trafienie
 */
void
uderz (object gracz, object cel, object bron_poprz)
{
    object bron = gracz->query_weapon(W_BOTH) ||
	          gracz->query_weapon(W_RIGHT) ||
	          gracz->query_weapon(W_LEFT);
    object mco = gracz->query_combat_object();

    set_this_player(gracz);

    gracz->remove_prop(LIVE_I_WKS_WAIT);
    
    if (environment (gracz) != environment (cel) )
    {
	write (cel->query_Imie (this_player(), PL_MIA) + " znikl ci z pola " +
	       "widzenia.\n");
	return;
    }

    if (bron != bron_poprz)
    {
	write ("Nie mozesz zmieniac broni w trakcie przygotowan do ciosu.\n");
	return;
    }

    if (czy_trafil(gracz, cel, bron))
	trafienie (gracz, cel, bron);
    else
	pudlo (gracz, cel, bron);

    gracz->add_prop(LIVE_I_WKS_REST, 1);
    set_alarm(15.0, 0.0, &rested(gracz));
}

/*
 * Wyliczenie damage'u i generowanie opisow dla trafien
 */
void
trafienie (object gracz, object cel, object bron)
{
    int pen = bron->query_pen();
    int skill = (gracz->query_skill (WKS_TOPOR) * 60) / 100 +
	        gracz->query_stat (SS_OCCUP) / 3;
    int wcpen = F_PENMOD (pen, skill);
    object zbroja;
    string w_co;
    mixed hitresult;

    if (DEBUG)
        dump_array ("wcpen:" + wcpen);
    /*
     * Ueee teraz musze wymyslec jakis sposob stopniowania damage'u :/
     * kurde nie lubie tego :P pewnie i tak Alvin mi to wywali :>
     * jako, ze zaraz wykorzystam hit_me powstrzymam sie od wyciagania
     * jakichs tam randomow na tym etapie, zeby nie robic tego dwa razy
     * docelowa wartosc miala byc 1.384, bede wspanialomyslny i zrobie 1.39
     */
    
    wcpen = (39 * wcpen) / 100 + // To zeby zaraz po wejsciu do gildii 
	                         // specjal mial jakas sile
	    (4 * gracz->query_skill (WKS_TOPOR) * wcpen) / 1000 +
	            // Tu mamy wplyw skilla specjala od 0 do 0.4 std. wcpena
	    (5 * gracz->query_stat (SS_OCCUP) * wcpen) / 1000;
                          // A tutaj stata od 0 do 0.6 std wcpena
                          // (przy zal. ze maks = 120)
    if (DEBUG)
        dump_array ("wcpen zmodyfikowany:" + wcpen);

    hitresult = cel->hit_me (wcpen, W_SLASH, 0, gracz, -1);
    if (DEBUG)
        dump_array (hitresult);
    zbroja = hitresult[4];
    if (gracz->query_attack() != cel)
	gracz->attack_object(cel);

    /*
     * Opisy dla specjala powinny miec forme trzech wiadomosci:
     * gracz->catch_msg("Tresc."); Informacja dla atakujacego gracza
     * cel->catch_msg("Tresc."); Informacje dla broniacego sie gracza
     * gracz->tell_watcher("Tresc."); Informacje dla postronnych osob.
     * gdzie:
     * gracz - obiekt wykonujacy specjal
     * cel - obiekt atakowany specjalem
     * bron - topor ktorym atakuje gracz
     * zbroja - zbroja ktora zparowala uderzenie (urzywana w jednym przyp.)
     * w_co - nazwa hitlokacji w ktora trafiono np. "glowe"
     *                przy humanoidach mozna zrobic odgorny podzial przy creature'ach
     *                konieczne jest wykorzystanie tego parametru
     */

    if (hitresult[3] == 0)
    {
        if (objectp (zbroja))
        {
            gracz->catch_msg ("Cios twojego " + QSHORT(bron, PL_DOP) + " zostal " +
	  	              "zparowany przez " + QSHORT (zbroja, PL_BIE) +
		              " " + QIMIE(cel, PL_DOP) + ".\n");
	    if(interactive(cel))
	         cel->catch_msg (QCIMIE (gracz, PL_MIA) + " trafia cie " + QSHORT
	  		         (bron, PL_NAR) + " ale jego cios zostal " +
			         "zparowany przez " + QSHORT (zbroja, PL_BIE)
			         + ".\n");
	    gracz->tell_watcher (QCIMIE (gracz, PL_MIA) + " trafia " + QIMIE
				 (cel, PL_BIE) + " " + QSHORT (bron, PL_NAR) + 
				 " ale jego cios zostaje zparowany przez " + 
				 QSHORT (zbroja, PL_BIE) + ".\n", cel);
        }
        else
        {
	    gracz->catch_msg ("Uderzasz " + QIMIE(cel, PL_BIE) + " " + QSHORT
		              (bron, PL_NAR) + " lecz twoj cios nie czyni " +
		              "mu / jej zadnych szkod.\n");
	    if(interactive(cel))
	        cel->catch_msg(QCIMIE(gracz, PL_MIA) + " uderza cie " + QSHORT
			       (bron, PL_MIA) + " lecz jego/jej cios nie czyni " +
			       "ci zadnych szkod.\n");
	    gracz->tell_watcher(QCIMIE(gracz, PL_MIA) + " uderza " + QIMIE 
			        (cel, PL_BIE) + " " + QSHORT(bron, PL_NAR) +
			        " nie czyniac mu/jej jednak zadnych szkod.\n", cel);
        }
	return;
    }
    if (DEBUG) 
        dump_array(w_co);

    if(!cel->query_hp())
    {
        gracz->catch_msg("Smiertelne trafienie w " + w_co + ".\n");
        cel->do_die(gracz);
        return;
    }
	
    switch (hitresult[0])
    {
    case 0..4:
        gracz->catch_msg("Slabe trafienie w " + w_co + ".\n");
        break;

    case 5..9:
        gracz->catch_msg("Lekkie zranienie w " + w_co + ".\n");
        break;

    case 10..19:
	gracz->catch_msg("Dosc mocne trafienie w " + w_co + ".\n");
	break;
		
    case 20..49:
	gracz->catch_msg("Mocne trafienie w " + w_co + ".\n");
	break;

    case 50..79:
	gracz->catch_msg("Bardzo mocne trafienie w " + w_co + ".\n");
	break;

    default:
	gracz->catch_msg("Potezne trafienie w " + w_co + ".\n");
    }
}

/*
 * Generowanie opisow dla nietrafien.
 */
void
pudlo(object gracz, object cel, object bron)
{
    if (random(100) < cel->query_skill(SS_DEFENCE))
    {
	gracz->catch_msg("Cel wykonal unik.\n");
    }
    else
    {
	gracz->catch_msg("Atakujacy nie trafil.\n");
    }
}

/*
 * Usuniecice propa odp. za przerwe miedzy specjalami
 */
void
rested(object gracz)
{
    gracz->remove_prop(LIVE_I_WKS_REST);
    gracz->catch_msg("Jestes gotow" + gracz->koncowka("y", "a") + " do zadania " +
		     "kolejnego ciosu.\n");
}
